ai-world-sdk 1.1.1 → 1.1.2
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/README.md +284 -3
- package/dist/__tests__/example.test.js +394 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/log.js +1 -1
- package/dist/openai_video_generation.d.ts +188 -0
- package/dist/openai_video_generation.js +287 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ TypeScript SDK for AI World Platform - 一个功能完整的 AI 应用开发 SDK
|
|
|
9
9
|
|
|
10
10
|
- 🤖 **聊天模型**: 兼容 LangChain.js 接口(OpenAI、Gemini、Claude、Doubao)
|
|
11
11
|
- 🎨 **图像生成**: 支持豆包 Seedream 和 Google Gemini
|
|
12
|
-
- 🎬 **视频生成**: 支持豆包 Seedance
|
|
12
|
+
- 🎬 **视频生成**: 支持豆包 Seedance 和 OpenAI Sora
|
|
13
13
|
- 📥 **下载代理**: 支持流式下载和普通下载任意 URL 的二进制文件
|
|
14
14
|
- 🔐 **用户认证**: 支持获取当前登录用户信息
|
|
15
15
|
- ⚙️ **全局配置**: 自动从浏览器环境获取配置,简化初始化
|
|
@@ -113,6 +113,8 @@ console.log('图像 URL:', geminiResult.data[0]?.url);
|
|
|
113
113
|
|
|
114
114
|
### 4. 视频生成
|
|
115
115
|
|
|
116
|
+
#### 豆包视频生成(Seedance)
|
|
117
|
+
|
|
116
118
|
```typescript
|
|
117
119
|
import { VideoGenerationClient } from 'ai-world-sdk';
|
|
118
120
|
|
|
@@ -136,6 +138,90 @@ if (result.status === 'succeeded') {
|
|
|
136
138
|
}
|
|
137
139
|
```
|
|
138
140
|
|
|
141
|
+
#### OpenAI 视频生成(Sora)
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { OpenAIVideoGenerationClient } from 'ai-world-sdk';
|
|
145
|
+
|
|
146
|
+
const openaiVideoClient = new OpenAIVideoGenerationClient({});
|
|
147
|
+
|
|
148
|
+
// 方式1: 文本生成视频
|
|
149
|
+
const task = await openaiVideoClient.generate({
|
|
150
|
+
prompt: 'A beautiful sunset over the ocean with waves crashing on the shore',
|
|
151
|
+
model: 'sora-2', // 或 'sora-2-pro'
|
|
152
|
+
provider: 'aihubmix', // 或 'api2img'
|
|
153
|
+
seconds: '4', // 4, 8, 或 12 秒
|
|
154
|
+
size: '1280x720' // '720x1280', '1280x720', '1024x1792', '1792x1024'
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
console.log('任务 ID:', task.id);
|
|
158
|
+
console.log('任务状态:', task.status);
|
|
159
|
+
|
|
160
|
+
// 方式2: 图像生成视频(图生视频)
|
|
161
|
+
const taskWithImage = await openaiVideoClient.generate({
|
|
162
|
+
prompt: 'Animate this scene with gentle movements',
|
|
163
|
+
input_reference: 'data:image/png;base64,iVBORw0KGgo...', // Base64 图像或 URL
|
|
164
|
+
model: 'sora-2',
|
|
165
|
+
provider: 'aihubmix',
|
|
166
|
+
seconds: '4'
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// 查询任务状态
|
|
170
|
+
const status = await openaiVideoClient.getTask(task.id, 'aihubmix');
|
|
171
|
+
console.log('当前状态:', status.status);
|
|
172
|
+
|
|
173
|
+
// 轮询等待完成
|
|
174
|
+
const result = await openaiVideoClient.waitForCompletion(task.id, 'aihubmix', {
|
|
175
|
+
maxAttempts: 60,
|
|
176
|
+
interval: 5000,
|
|
177
|
+
onProgress: (status) => {
|
|
178
|
+
console.log('当前状态:', status.status);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (result.status === 'completed') {
|
|
183
|
+
console.log('视频生成成功!');
|
|
184
|
+
|
|
185
|
+
// 流式下载视频
|
|
186
|
+
const videoBlob = await openaiVideoClient.downloadVideo(
|
|
187
|
+
result.id,
|
|
188
|
+
'aihubmix', // provider
|
|
189
|
+
'video' // 'video' 或 'thumbnail'
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
console.log('视频大小:', (videoBlob.size / 1024 / 1024).toFixed(2), 'MB');
|
|
193
|
+
|
|
194
|
+
// 在浏览器中下载
|
|
195
|
+
const url = URL.createObjectURL(videoBlob);
|
|
196
|
+
const a = document.createElement('a');
|
|
197
|
+
a.href = url;
|
|
198
|
+
a.download = 'sora_video.mp4';
|
|
199
|
+
a.click();
|
|
200
|
+
URL.revokeObjectURL(url);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 一键生成并等待(简化版)
|
|
204
|
+
const completeResult = await openaiVideoClient.generateAndWait({
|
|
205
|
+
prompt: 'A futuristic city skyline',
|
|
206
|
+
model: 'sora-2',
|
|
207
|
+
provider: 'aihubmix',
|
|
208
|
+
seconds: '4'
|
|
209
|
+
}, {
|
|
210
|
+
maxAttempts: 60,
|
|
211
|
+
interval: 5000,
|
|
212
|
+
onProgress: (status) => console.log('状态:', status.status)
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (completeResult.status === 'completed') {
|
|
216
|
+
const videoBlob = await openaiVideoClient.downloadVideo(
|
|
217
|
+
completeResult.id,
|
|
218
|
+
'aihubmix',
|
|
219
|
+
'video'
|
|
220
|
+
);
|
|
221
|
+
console.log('一键生成完成,视频大小:', videoBlob.size);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
139
225
|
### 5. 用户认证
|
|
140
226
|
|
|
141
227
|
```typescript
|
|
@@ -378,7 +464,7 @@ const secondResponse = await client.chat({
|
|
|
378
464
|
|
|
379
465
|
### 视频生成
|
|
380
466
|
|
|
381
|
-
#### VideoGenerationClient
|
|
467
|
+
#### VideoGenerationClient(豆包 Seedance)
|
|
382
468
|
|
|
383
469
|
```typescript
|
|
384
470
|
const client = new VideoGenerationClient({});
|
|
@@ -403,6 +489,53 @@ const result = await client.poll(task.id, {
|
|
|
403
489
|
});
|
|
404
490
|
```
|
|
405
491
|
|
|
492
|
+
#### OpenAIVideoGenerationClient(OpenAI Sora)
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
const client = new OpenAIVideoGenerationClient({});
|
|
496
|
+
|
|
497
|
+
// 文本生成视频
|
|
498
|
+
const task = await client.generate({
|
|
499
|
+
prompt: 'A beautiful sunset',
|
|
500
|
+
model: 'sora-2', // 可选: sora-2, sora-2-pro
|
|
501
|
+
provider: 'openai', // 可选: openai, aihubmix, api2img
|
|
502
|
+
seconds: '4', // 可选: 4, 8, 12
|
|
503
|
+
size: '1280x720', // 可选: 720x1280, 1280x720, 1024x1792, 1792x1024
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// 图像生成视频
|
|
507
|
+
const taskFromImage = await client.generate({
|
|
508
|
+
prompt: 'Animate this scene',
|
|
509
|
+
input_reference: 'data:image/png;base64,iVBORw0KGgo...', // Base64 或 URL
|
|
510
|
+
model: 'sora-2',
|
|
511
|
+
seconds: '8',
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// 查询状态
|
|
515
|
+
const status = await client.getTask(task.id);
|
|
516
|
+
|
|
517
|
+
// 轮询直到完成
|
|
518
|
+
const result = await client.waitForCompletion(task.id, {
|
|
519
|
+
maxAttempts: 60,
|
|
520
|
+
interval: 5000,
|
|
521
|
+
onProgress: (status) => {
|
|
522
|
+
console.log('状态:', status.status);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// 下载视频
|
|
527
|
+
const videoBlob = await client.downloadVideo(task.id, {
|
|
528
|
+
variant: 'video' // 或 'thumbnail'
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// 一键生成并等待
|
|
532
|
+
const finalResult = await client.generateAndWait({
|
|
533
|
+
prompt: 'A futuristic city',
|
|
534
|
+
model: 'sora-2',
|
|
535
|
+
seconds: '4'
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
406
539
|
### 下载代理
|
|
407
540
|
|
|
408
541
|
#### DownloadClient
|
|
@@ -1064,6 +1197,8 @@ if (userInfo.avatar_url) {
|
|
|
1064
1197
|
|
|
1065
1198
|
### 视频生成工作流
|
|
1066
1199
|
|
|
1200
|
+
#### 豆包视频生成(Doubao Seedance)
|
|
1201
|
+
|
|
1067
1202
|
```typescript
|
|
1068
1203
|
import { VideoGenerationClient } from 'ai-world-sdk';
|
|
1069
1204
|
|
|
@@ -1093,6 +1228,131 @@ if (result.status === 'succeeded') {
|
|
|
1093
1228
|
}
|
|
1094
1229
|
```
|
|
1095
1230
|
|
|
1231
|
+
#### OpenAI 视频生成(Sora)
|
|
1232
|
+
|
|
1233
|
+
```typescript
|
|
1234
|
+
import { OpenAIVideoGenerationClient } from 'ai-world-sdk';
|
|
1235
|
+
|
|
1236
|
+
const client = new OpenAIVideoGenerationClient({});
|
|
1237
|
+
|
|
1238
|
+
// 1. 文本生成视频
|
|
1239
|
+
const task = await client.generate({
|
|
1240
|
+
prompt: 'A serene mountain landscape with a flowing river',
|
|
1241
|
+
model: 'sora-2', // 'sora-2' 或 'sora-2-pro'
|
|
1242
|
+
provider: 'aihubmix', // 'aihubmix' 或 'api2img'
|
|
1243
|
+
seconds: '4', // '4', '8', 或 '12'
|
|
1244
|
+
size: '1280x720' // '720x1280', '1280x720', '1024x1792', '1792x1024'
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
console.log('任务已创建:', task.id);
|
|
1248
|
+
console.log('任务状态:', task.status);
|
|
1249
|
+
|
|
1250
|
+
// 2. 查询任务状态
|
|
1251
|
+
const status = await client.getTask(task.id, 'aihubmix');
|
|
1252
|
+
console.log('当前状态:', status.status);
|
|
1253
|
+
|
|
1254
|
+
// 3. 轮询等待完成
|
|
1255
|
+
const result = await client.waitForCompletion(
|
|
1256
|
+
task.id,
|
|
1257
|
+
'aihubmix', // provider 参数
|
|
1258
|
+
{
|
|
1259
|
+
maxAttempts: 60,
|
|
1260
|
+
interval: 5000,
|
|
1261
|
+
onProgress: (status) => {
|
|
1262
|
+
console.log(`状态: ${status.status}`);
|
|
1263
|
+
if (status.status === 'in_progress') {
|
|
1264
|
+
console.log('正在生成...');
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
);
|
|
1269
|
+
|
|
1270
|
+
if (result.status === 'completed') {
|
|
1271
|
+
console.log('✅ 视频生成成功!');
|
|
1272
|
+
|
|
1273
|
+
// 4. 流式下载视频
|
|
1274
|
+
const videoBlob = await client.downloadVideo(
|
|
1275
|
+
result.id,
|
|
1276
|
+
'aihubmix', // provider
|
|
1277
|
+
'video' // 'video' 或 'thumbnail'
|
|
1278
|
+
);
|
|
1279
|
+
|
|
1280
|
+
console.log('视频大小:', (videoBlob.size / 1024 / 1024).toFixed(2), 'MB');
|
|
1281
|
+
console.log('视频类型:', videoBlob.type);
|
|
1282
|
+
|
|
1283
|
+
// 在浏览器中创建下载链接
|
|
1284
|
+
const url = URL.createObjectURL(videoBlob);
|
|
1285
|
+
const a = document.createElement('a');
|
|
1286
|
+
a.href = url;
|
|
1287
|
+
a.download = `sora_video_${result.id}.mp4`;
|
|
1288
|
+
a.click();
|
|
1289
|
+
URL.revokeObjectURL(url);
|
|
1290
|
+
|
|
1291
|
+
// 也可以下载缩略图
|
|
1292
|
+
const thumbnail = await client.downloadVideo(
|
|
1293
|
+
result.id,
|
|
1294
|
+
'aihubmix',
|
|
1295
|
+
'thumbnail'
|
|
1296
|
+
);
|
|
1297
|
+
console.log('缩略图大小:', (thumbnail.size / 1024).toFixed(2), 'KB');
|
|
1298
|
+
} else if (result.status === 'failed') {
|
|
1299
|
+
console.error('❌ 生成失败:', result.error);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// 一键生成并等待(简化版)
|
|
1303
|
+
try {
|
|
1304
|
+
const result2 = await client.generateAndWait({
|
|
1305
|
+
prompt: 'A futuristic city with flying cars at night',
|
|
1306
|
+
model: 'sora-2',
|
|
1307
|
+
provider: 'aihubmix',
|
|
1308
|
+
seconds: '8',
|
|
1309
|
+
size: '1280x720'
|
|
1310
|
+
}, {
|
|
1311
|
+
maxAttempts: 60,
|
|
1312
|
+
interval: 5000,
|
|
1313
|
+
onProgress: (status) => console.log('进度:', status.status)
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
console.log('视频生成完成:', result2.id);
|
|
1317
|
+
|
|
1318
|
+
// 流式下载
|
|
1319
|
+
const video = await client.downloadVideo(
|
|
1320
|
+
result2.id,
|
|
1321
|
+
'aihubmix',
|
|
1322
|
+
'video'
|
|
1323
|
+
);
|
|
1324
|
+
console.log('视频大小:', (video.size / 1024 / 1024).toFixed(2), 'MB');
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
console.error('视频生成失败:', error);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// 图像生成视频示例
|
|
1330
|
+
const imageToVideoTask = await client.generate({
|
|
1331
|
+
prompt: 'Make this scene come alive with gentle movements',
|
|
1332
|
+
input_reference: 'data:image/png;base64,iVBORw0KGgo...', // 图像 base64 或 URL
|
|
1333
|
+
model: 'sora-2',
|
|
1334
|
+
provider: 'aihubmix',
|
|
1335
|
+
seconds: '4'
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
const imageToVideoResult = await client.waitForCompletion(
|
|
1339
|
+
imageToVideoTask.id,
|
|
1340
|
+
'aihubmix'
|
|
1341
|
+
);
|
|
1342
|
+
|
|
1343
|
+
if (imageToVideoResult.status === 'completed') {
|
|
1344
|
+
console.log('图生视频完成:', imageToVideoResult.id);
|
|
1345
|
+
|
|
1346
|
+
// 下载视频
|
|
1347
|
+
const videoBlob = await client.downloadVideo(
|
|
1348
|
+
imageToVideoResult.id,
|
|
1349
|
+
'aihubmix',
|
|
1350
|
+
'video'
|
|
1351
|
+
);
|
|
1352
|
+
console.log('视频已下载,大小:', videoBlob.size);
|
|
1353
|
+
}
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1096
1356
|
### 用户认证工作流
|
|
1097
1357
|
|
|
1098
1358
|
```typescript
|
|
@@ -1253,7 +1513,28 @@ for await (const chunk of client.streamDownload({
|
|
|
1253
1513
|
|
|
1254
1514
|
### 视频生成模型
|
|
1255
1515
|
|
|
1256
|
-
|
|
1516
|
+
#### 豆包 Seedance
|
|
1517
|
+
|
|
1518
|
+
| 模型 | Provider | 说明 | 参数 |
|
|
1519
|
+
|------|----------|------|------|
|
|
1520
|
+
| `doubao-seedance-1-0-pro-fast-251015` | `doubao` | 快速版(推荐) | 时长: 1-10秒,宽高比: 16:9/9:16/1:1 |
|
|
1521
|
+
| `doubao-seedance-1-0-pro-250528` | `doubao` | 专业版 | 时长: 1-10秒,宽高比: 16:9/9:16/1:1 |
|
|
1522
|
+
| `doubao-seedance-1-0-lite-t2v-250428` | `doubao` | 轻量版(文生视频) | 时长: 1-10秒 |
|
|
1523
|
+
| `doubao-seedance-1-0-lite-i2v-250428` | `doubao` | 轻量版(图生视频) | 时长: 1-10秒 |
|
|
1524
|
+
|
|
1525
|
+
#### OpenAI Sora
|
|
1526
|
+
|
|
1527
|
+
| 模型 | Provider | 说明 | 参数 |
|
|
1528
|
+
|------|----------|------|------|
|
|
1529
|
+
| `sora-2` | `aihubmix` / `api2img` | 标准模型(默认) | 时长: 4/8/12秒,分辨率: 720x1280, 1280x720, 1024x1792, 1792x1024 |
|
|
1530
|
+
| `sora-2-pro` | `aihubmix` / `api2img` | 专业版模型 | 时长: 4/8/12秒,分辨率: 720x1280, 1280x720, 1024x1792, 1792x1024 |
|
|
1531
|
+
|
|
1532
|
+
**特性说明:**
|
|
1533
|
+
- **豆包 Seedance**: 支持文本生成视频和图像生成视频,URL 直接返回
|
|
1534
|
+
- **OpenAI Sora**: 支持文本生成视频和图像生成视频(Base64/URL),需要流式下载
|
|
1535
|
+
- **Provider 选择**:
|
|
1536
|
+
- 豆包: 仅支持 `doubao` provider
|
|
1537
|
+
- OpenAI: 支持 `aihubmix` 和 `api2img` provider(推荐使用 `aihubmix`)
|
|
1257
1538
|
|
|
1258
1539
|
## 错误处理
|
|
1259
1540
|
|
|
@@ -44,7 +44,7 @@ const fs_1 = require("fs");
|
|
|
44
44
|
dotenv.config();
|
|
45
45
|
index_1.sdkConfig.setBaseUrl("http://localhost:8000");
|
|
46
46
|
index_1.sdkConfig.setToken(process.env.AUTH_TOKEN || process.env.TOKEN || "");
|
|
47
|
-
|
|
47
|
+
index_1.sdkConfig.setDebug(true);
|
|
48
48
|
function extractTextFromChunk(chunk) {
|
|
49
49
|
if (typeof chunk.content === "string") {
|
|
50
50
|
return chunk.content;
|
|
@@ -1148,4 +1148,397 @@ describe("Langchain SDK Tests", () => {
|
|
|
1148
1148
|
console.log("响应内容:", content);
|
|
1149
1149
|
}
|
|
1150
1150
|
}, 30000);
|
|
1151
|
+
// ========== OpenAI 视频生成测试 ==========
|
|
1152
|
+
test("OpenAIVideoGenerationClient - 创建视频生成任务(文本)", async () => {
|
|
1153
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1154
|
+
const task = await openaiVideoClient.generate({
|
|
1155
|
+
prompt: "A beautiful sunset over the ocean with waves crashing on the shore",
|
|
1156
|
+
model: "sora-2",
|
|
1157
|
+
provider: "aihubmix",
|
|
1158
|
+
seconds: "4",
|
|
1159
|
+
size: "1280x720",
|
|
1160
|
+
});
|
|
1161
|
+
expect(task).toBeDefined();
|
|
1162
|
+
expect(task.id).toBeDefined();
|
|
1163
|
+
expect(typeof task.id).toBe("string");
|
|
1164
|
+
expect(task.status).toBeDefined();
|
|
1165
|
+
expect(["queued", "in_progress", "completed", "failed"]).toContain(task.status);
|
|
1166
|
+
console.log("✅ OpenAI 视频生成任务创建成功(文本)");
|
|
1167
|
+
console.log("任务 ID:", task.id);
|
|
1168
|
+
console.log("任务状态:", task.status);
|
|
1169
|
+
}, 60000);
|
|
1170
|
+
test("OpenAIVideoGenerationClient - 创建视频生成任务(图像)", async () => {
|
|
1171
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1172
|
+
// 使用一个小的 base64 图像
|
|
1173
|
+
const base64Image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAJCAIAAACAMfp5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFgmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDIgNzkuZGJhM2RhM2I1LCAyMDIzLzEyLzE1LTEwOjQyOjM3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB0aWZmOk9yaWVudGF0aW9uPSIxIiBleGlmOkNvbG9yU3BhY2U9IjEiIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSI4IiBleGlmOlBpeGVsWURpbWVuc2lvbj0iOSIgeG1wOkNyZWF0ZURhdGU9IjIwMjUtMTItMTlUMTI6MDY6MDMrMDg6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5Y2IwNmRjYi04MmI0LTQ3ODctYmQ1Ny1lYWI5MzE5MzkyYzUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6OWNiMDZkY2ItODJiNC00Nzg3LWJkNTctZWFiOTMxOTM5MmM1IiBzdEV2dDp3aGVuPSIyMDI1LTEyLTE5VDEyOjA2OjM1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjUuNiAoTWFjaW50b3NoKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6KNh+8AAAAEElEQVQIHWNgYPiPAw0PCQA/Vke5jW7wRQAAAABJRU5ErkJggg==";
|
|
1174
|
+
const task = await openaiVideoClient.generate({
|
|
1175
|
+
prompt: "Animate this scene with gentle movements",
|
|
1176
|
+
input_reference: base64Image,
|
|
1177
|
+
model: "sora-2",
|
|
1178
|
+
provider: "aihubmix",
|
|
1179
|
+
seconds: "4",
|
|
1180
|
+
});
|
|
1181
|
+
console.log("task:", task);
|
|
1182
|
+
expect(task).toBeDefined();
|
|
1183
|
+
expect(task.id).toBeDefined();
|
|
1184
|
+
expect(typeof task.id).toBe("string");
|
|
1185
|
+
console.log("✅ OpenAI 视频生成任务创建成功(图像)");
|
|
1186
|
+
console.log("任务 ID:", task.id);
|
|
1187
|
+
}, 60000);
|
|
1188
|
+
test("OpenAIVideoGenerationClient - 查询任务状态", async () => {
|
|
1189
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1190
|
+
// // 先创建一个任务
|
|
1191
|
+
// const createTask = await openaiVideoClient.generate({
|
|
1192
|
+
// prompt: "A serene mountain landscape",
|
|
1193
|
+
// model: "sora-2",
|
|
1194
|
+
// provider: "aihubmix",
|
|
1195
|
+
// seconds: "4",
|
|
1196
|
+
// });
|
|
1197
|
+
// console.log("createTask:", createTask);
|
|
1198
|
+
// expect(createTask.id).toBeDefined();
|
|
1199
|
+
// 查询任务状态
|
|
1200
|
+
let taskId = "eyJtb2RlbCI6InNvcmEtMiIsImlkIjoidmlkZW9fNjk0YmYxYzZjNTEwODE5MDliZjBlNDc5ZDI3OGU5ODYifQchannel2361";
|
|
1201
|
+
// 轮询任务(使用较短的超时时间用于测试)
|
|
1202
|
+
try {
|
|
1203
|
+
const result = await openaiVideoClient.waitForCompletion(taskId, "aihubmix", {
|
|
1204
|
+
maxAttempts: 30, // 最多轮询 30 次
|
|
1205
|
+
interval: 5000, // 每 5 秒轮询一次
|
|
1206
|
+
onProgress: (status) => {
|
|
1207
|
+
console.log(`进度更新: ${status.status}`);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
console.log("--------------------------------");
|
|
1211
|
+
console.log("result:", JSON.stringify(result, null, 2));
|
|
1212
|
+
console.log("--------------------------------");
|
|
1213
|
+
expect(result).toBeDefined();
|
|
1214
|
+
expect(["completed", "failed"]).toContain(result.status);
|
|
1215
|
+
console.log("✅ OpenAI 视频任务轮询完成");
|
|
1216
|
+
console.log("最终状态:", result.status);
|
|
1217
|
+
if (result.status === "completed") {
|
|
1218
|
+
console.log("视频 ID:", result.id);
|
|
1219
|
+
}
|
|
1220
|
+
else if (result.error) {
|
|
1221
|
+
console.log("错误信息:", result.error);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
catch (error) {
|
|
1225
|
+
// 如果超时,这是正常的(视频生成需要时间)
|
|
1226
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1227
|
+
console.log("⏭️ 轮询超时(正常,视频生成需要较长时间)");
|
|
1228
|
+
}
|
|
1229
|
+
else {
|
|
1230
|
+
throw error;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}, 60000);
|
|
1234
|
+
test("OpenAIVideoGenerationClient - 轮询等待完成", async () => {
|
|
1235
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1236
|
+
// 创建任务
|
|
1237
|
+
const createTask = await openaiVideoClient.generate({
|
|
1238
|
+
prompt: "A short video of clouds moving across the sky",
|
|
1239
|
+
model: "sora-2",
|
|
1240
|
+
provider: "aihubmix",
|
|
1241
|
+
seconds: "4",
|
|
1242
|
+
});
|
|
1243
|
+
expect(createTask.id).toBeDefined();
|
|
1244
|
+
console.log("任务创建:", createTask.id);
|
|
1245
|
+
// 轮询任务(使用较短的超时时间用于测试)
|
|
1246
|
+
try {
|
|
1247
|
+
const result = await openaiVideoClient.waitForCompletion(createTask.id, "aihubmix", {
|
|
1248
|
+
maxAttempts: 30, // 最多轮询 30 次
|
|
1249
|
+
interval: 5000, // 每 5 秒轮询一次
|
|
1250
|
+
onProgress: (status) => {
|
|
1251
|
+
console.log(`进度更新: ${status.status}`);
|
|
1252
|
+
}
|
|
1253
|
+
});
|
|
1254
|
+
expect(result).toBeDefined();
|
|
1255
|
+
expect(["completed", "failed"]).toContain(result.status);
|
|
1256
|
+
console.log("✅ OpenAI 视频任务轮询完成");
|
|
1257
|
+
console.log("最终状态:", result.status);
|
|
1258
|
+
if (result.status === "completed") {
|
|
1259
|
+
console.log("视频 ID:", result.id);
|
|
1260
|
+
}
|
|
1261
|
+
else if (result.error) {
|
|
1262
|
+
console.log("错误信息:", result.error);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
catch (error) {
|
|
1266
|
+
// 如果超时,这是正常的(视频生成需要时间)
|
|
1267
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1268
|
+
console.log("⏭️ 轮询超时(正常,视频生成需要较长时间)");
|
|
1269
|
+
}
|
|
1270
|
+
else {
|
|
1271
|
+
throw error;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}, 180000);
|
|
1275
|
+
test("OpenAIVideoGenerationClient - 一键生成并等待", async () => {
|
|
1276
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1277
|
+
try {
|
|
1278
|
+
const result = await openaiVideoClient.generateAndWait({
|
|
1279
|
+
prompt: "A futuristic city skyline",
|
|
1280
|
+
model: "sora-2",
|
|
1281
|
+
provider: "aihubmix",
|
|
1282
|
+
seconds: "4",
|
|
1283
|
+
size: "1280x720"
|
|
1284
|
+
}, {
|
|
1285
|
+
maxAttempts: 30,
|
|
1286
|
+
interval: 5000,
|
|
1287
|
+
onProgress: (status) => {
|
|
1288
|
+
console.log("状态:", status.status);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
expect(result).toBeDefined();
|
|
1292
|
+
expect(result.id).toBeDefined();
|
|
1293
|
+
expect(["completed", "failed"]).toContain(result.status);
|
|
1294
|
+
console.log("✅ OpenAI 一键生成并等待测试完成");
|
|
1295
|
+
console.log("最终状态:", result.status);
|
|
1296
|
+
}
|
|
1297
|
+
catch (error) {
|
|
1298
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1299
|
+
console.log("⏭️ 轮询超时(正常)");
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
throw error;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}, 180000);
|
|
1306
|
+
test("OpenAIVideoGenerationClient - 不同 provider 测试", async () => {
|
|
1307
|
+
const providers = ["api2img"];
|
|
1308
|
+
for (const provider of providers) {
|
|
1309
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1310
|
+
const task = await openaiVideoClient.generate({
|
|
1311
|
+
prompt: "A simple animation",
|
|
1312
|
+
model: "sora-2",
|
|
1313
|
+
provider: provider,
|
|
1314
|
+
seconds: "4",
|
|
1315
|
+
});
|
|
1316
|
+
expect(task).toBeDefined();
|
|
1317
|
+
expect(task.id).toBeDefined();
|
|
1318
|
+
console.log(`✅ provider ${provider} 测试成功,任务 ID: ${task.id}`);
|
|
1319
|
+
}
|
|
1320
|
+
}, 120000);
|
|
1321
|
+
test("OpenAIVideoGenerationClient - 不同 seconds 参数测试", async () => {
|
|
1322
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1323
|
+
const secondsOptions = ["4", "8"];
|
|
1324
|
+
for (const seconds of secondsOptions) {
|
|
1325
|
+
const task = await openaiVideoClient.generate({
|
|
1326
|
+
prompt: "A video clip",
|
|
1327
|
+
model: "sora-2",
|
|
1328
|
+
provider: "aihubmix",
|
|
1329
|
+
seconds: seconds,
|
|
1330
|
+
});
|
|
1331
|
+
expect(task).toBeDefined();
|
|
1332
|
+
expect(task.id).toBeDefined();
|
|
1333
|
+
console.log(`✅ seconds ${seconds} 测试成功,任务 ID: ${task.id}`);
|
|
1334
|
+
}
|
|
1335
|
+
}, 120000);
|
|
1336
|
+
test("OpenAIVideoGenerationClient - 不同 size 参数测试", async () => {
|
|
1337
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1338
|
+
const sizeOptions = [
|
|
1339
|
+
"1280x720",
|
|
1340
|
+
"720x1280",
|
|
1341
|
+
];
|
|
1342
|
+
for (const size of sizeOptions) {
|
|
1343
|
+
const task = await openaiVideoClient.generate({
|
|
1344
|
+
prompt: "A landscape video",
|
|
1345
|
+
model: "sora-2",
|
|
1346
|
+
provider: "aihubmix",
|
|
1347
|
+
seconds: "4",
|
|
1348
|
+
size: size,
|
|
1349
|
+
});
|
|
1350
|
+
expect(task).toBeDefined();
|
|
1351
|
+
expect(task.id).toBeDefined();
|
|
1352
|
+
console.log(`✅ size ${size} 测试成功,任务 ID: ${task.id}`);
|
|
1353
|
+
}
|
|
1354
|
+
}, 120000);
|
|
1355
|
+
test("OpenAIVideoGenerationClient - 下载视频测试", async () => {
|
|
1356
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1357
|
+
let taskId = "eyJtb2RlbCI6InNvcmEtMiIsImlkIjoidmlkZW9fNjk0YmYxYzZjNTEwODE5MDliZjBlNDc5ZDI3OGU5ODYifQchannel2361";
|
|
1358
|
+
// 等待任务完成
|
|
1359
|
+
try {
|
|
1360
|
+
const result = await openaiVideoClient.waitForCompletion(taskId, "aihubmix", {
|
|
1361
|
+
maxAttempts: 30,
|
|
1362
|
+
interval: 5000,
|
|
1363
|
+
});
|
|
1364
|
+
console.log("result:", result);
|
|
1365
|
+
if (result.status === "completed") {
|
|
1366
|
+
// 下载视频
|
|
1367
|
+
const videoBlob = await openaiVideoClient.downloadVideo(result.id, "aihubmix", "video");
|
|
1368
|
+
expect(videoBlob).toBeDefined();
|
|
1369
|
+
expect(videoBlob instanceof Blob).toBe(true);
|
|
1370
|
+
expect(videoBlob.size).toBeGreaterThan(0);
|
|
1371
|
+
console.log("✅ OpenAI 视频下载测试成功");
|
|
1372
|
+
console.log(`视频大小: ${(videoBlob.size / 1024 / 1024).toFixed(2)} MB`);
|
|
1373
|
+
}
|
|
1374
|
+
else {
|
|
1375
|
+
console.log("⏭️ 任务未完成,跳过下载测试");
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
catch (error) {
|
|
1379
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1380
|
+
console.log("⏭️ 轮询超时,跳过下载测试");
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
throw error;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}, 180000);
|
|
1387
|
+
test("OpenAIVideoGenerationClient - 下载缩略图测试", async () => {
|
|
1388
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1389
|
+
// 创建任务
|
|
1390
|
+
const createTask = await openaiVideoClient.generate({
|
|
1391
|
+
prompt: "A simple scene for thumbnail test",
|
|
1392
|
+
model: "sora-2",
|
|
1393
|
+
provider: "aihubmix",
|
|
1394
|
+
seconds: "4",
|
|
1395
|
+
});
|
|
1396
|
+
expect(createTask.id).toBeDefined();
|
|
1397
|
+
console.log("创建任务:", createTask.id);
|
|
1398
|
+
// 等待任务完成
|
|
1399
|
+
try {
|
|
1400
|
+
const result = await openaiVideoClient.waitForCompletion(createTask.id, "aihubmix", {
|
|
1401
|
+
maxAttempts: 30,
|
|
1402
|
+
interval: 5000,
|
|
1403
|
+
});
|
|
1404
|
+
if (result.status === "completed") {
|
|
1405
|
+
// 下载缩略图
|
|
1406
|
+
const thumbnailBlob = await openaiVideoClient.downloadVideo(result.id, "aihubmix", "thumbnail");
|
|
1407
|
+
expect(thumbnailBlob).toBeDefined();
|
|
1408
|
+
expect(thumbnailBlob instanceof Blob).toBe(true);
|
|
1409
|
+
expect(thumbnailBlob.size).toBeGreaterThan(0);
|
|
1410
|
+
console.log("✅ OpenAI 缩略图下载测试成功");
|
|
1411
|
+
console.log(`缩略图大小: ${(thumbnailBlob.size / 1024).toFixed(2)} KB`);
|
|
1412
|
+
}
|
|
1413
|
+
else {
|
|
1414
|
+
console.log("⏭️ 任务未完成,跳过缩略图下载测试");
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
catch (error) {
|
|
1418
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1419
|
+
console.log("⏭️ 轮询超时,跳过缩略图下载测试");
|
|
1420
|
+
}
|
|
1421
|
+
else {
|
|
1422
|
+
throw error;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}, 180000);
|
|
1426
|
+
test("OpenAIVideoGenerationClient - 不同 provider 下载测试", async () => {
|
|
1427
|
+
const providers = ["api2img"];
|
|
1428
|
+
for (const provider of providers) {
|
|
1429
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1430
|
+
// 创建任务
|
|
1431
|
+
const createTask = await openaiVideoClient.generate({
|
|
1432
|
+
prompt: "A test video for download",
|
|
1433
|
+
model: "sora-2",
|
|
1434
|
+
provider: provider,
|
|
1435
|
+
seconds: "4",
|
|
1436
|
+
});
|
|
1437
|
+
expect(createTask.id).toBeDefined();
|
|
1438
|
+
console.log(`${provider} 创建任务:`, createTask.id);
|
|
1439
|
+
try {
|
|
1440
|
+
const result = await openaiVideoClient.waitForCompletion(createTask.id, provider, {
|
|
1441
|
+
maxAttempts: 30,
|
|
1442
|
+
interval: 5000,
|
|
1443
|
+
});
|
|
1444
|
+
if (result.status === "completed") {
|
|
1445
|
+
// 下载视频
|
|
1446
|
+
const videoBlob = await openaiVideoClient.downloadVideo(result.id, provider, "video");
|
|
1447
|
+
expect(videoBlob).toBeDefined();
|
|
1448
|
+
expect(videoBlob instanceof Blob).toBe(true);
|
|
1449
|
+
expect(videoBlob.size).toBeGreaterThan(0);
|
|
1450
|
+
console.log(`✅ provider ${provider} 下载测试成功`);
|
|
1451
|
+
console.log(`视频大小: ${(videoBlob.size / 1024 / 1024).toFixed(2)} MB`);
|
|
1452
|
+
}
|
|
1453
|
+
else {
|
|
1454
|
+
console.log(`⏭️ ${provider} 任务未完成,跳过下载测试`);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
catch (error) {
|
|
1458
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1459
|
+
console.log(`⏭️ ${provider} 轮询超时,跳过下载测试`);
|
|
1460
|
+
}
|
|
1461
|
+
else {
|
|
1462
|
+
throw error;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}, 360000);
|
|
1467
|
+
test("OpenAIVideoGenerationClient - 直接下载已完成的视频", async () => {
|
|
1468
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1469
|
+
// 使用一个已知完成的视频 ID(从前面测试中获取)
|
|
1470
|
+
// 注意:这需要一个真实的已完成视频 ID,此处仅作示例
|
|
1471
|
+
const knownVideoId = "eyJtb2RlbCI6InNvcmEtMiIsImlkIjoidmlkZW9fNjk0YmYxYzZjNTEwODE5MDliZjBlNDc5ZDI3OGU5ODYifQchannel2361";
|
|
1472
|
+
try {
|
|
1473
|
+
// 先查询状态
|
|
1474
|
+
const status = await openaiVideoClient.getTask(knownVideoId, "aihubmix");
|
|
1475
|
+
if (status.status === "completed") {
|
|
1476
|
+
// 下载视频
|
|
1477
|
+
const videoBlob = await openaiVideoClient.downloadVideo(knownVideoId, "aihubmix", "video");
|
|
1478
|
+
expect(videoBlob).toBeDefined();
|
|
1479
|
+
expect(videoBlob instanceof Blob).toBe(true);
|
|
1480
|
+
expect(videoBlob.size).toBeGreaterThan(0);
|
|
1481
|
+
console.log("✅ 直接下载已完成视频测试成功");
|
|
1482
|
+
console.log(`视频大小: ${(videoBlob.size / 1024 / 1024).toFixed(2)} MB`);
|
|
1483
|
+
}
|
|
1484
|
+
else {
|
|
1485
|
+
console.log(`⏭️ 视频状态: ${status.status},跳过下载测试`);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
catch (error) {
|
|
1489
|
+
// 视频可能已过期或不存在
|
|
1490
|
+
console.log("⏭️ 视频不存在或已过期,跳过测试");
|
|
1491
|
+
}
|
|
1492
|
+
}, 60000);
|
|
1493
|
+
test("OpenAIVideoGenerationClient - 完整流程:生成、等待、下载", async () => {
|
|
1494
|
+
const openaiVideoClient = new index_1.OpenAIVideoGenerationClient({});
|
|
1495
|
+
try {
|
|
1496
|
+
console.log("1️⃣ 开始生成视频...");
|
|
1497
|
+
const task = await openaiVideoClient.generate({
|
|
1498
|
+
prompt: "A complete workflow test video",
|
|
1499
|
+
model: "sora-2",
|
|
1500
|
+
provider: "aihubmix",
|
|
1501
|
+
seconds: "4",
|
|
1502
|
+
});
|
|
1503
|
+
expect(task.id).toBeDefined();
|
|
1504
|
+
console.log(`任务创建成功: ${task.id}`);
|
|
1505
|
+
console.log("2️⃣ 等待视频生成完成...");
|
|
1506
|
+
const result = await openaiVideoClient.waitForCompletion(task.id, "aihubmix", {
|
|
1507
|
+
maxAttempts: 30,
|
|
1508
|
+
interval: 5000,
|
|
1509
|
+
onProgress: (status) => {
|
|
1510
|
+
console.log(` 进度: ${status.status}`);
|
|
1511
|
+
},
|
|
1512
|
+
});
|
|
1513
|
+
expect(result.status).toBeDefined();
|
|
1514
|
+
console.log(`视频生成完成: ${result.status}`);
|
|
1515
|
+
if (result.status === "completed") {
|
|
1516
|
+
console.log("3️⃣ 下载视频...");
|
|
1517
|
+
const videoBlob = await openaiVideoClient.downloadVideo(result.id, "aihubmix", "video");
|
|
1518
|
+
expect(videoBlob).toBeDefined();
|
|
1519
|
+
expect(videoBlob instanceof Blob).toBe(true);
|
|
1520
|
+
expect(videoBlob.size).toBeGreaterThan(0);
|
|
1521
|
+
console.log("✅ 完整流程测试成功");
|
|
1522
|
+
console.log(` - 任务 ID: ${result.id}`);
|
|
1523
|
+
console.log(` - 视频大小: ${(videoBlob.size / 1024 / 1024).toFixed(2)} MB`);
|
|
1524
|
+
// 也下载缩略图
|
|
1525
|
+
console.log("4️⃣ 下载缩略图...");
|
|
1526
|
+
const thumbnailBlob = await openaiVideoClient.downloadVideo(result.id, "aihubmix", "thumbnail");
|
|
1527
|
+
expect(thumbnailBlob).toBeDefined();
|
|
1528
|
+
expect(thumbnailBlob instanceof Blob).toBe(true);
|
|
1529
|
+
console.log(` - 缩略图大小: ${(thumbnailBlob.size / 1024).toFixed(2)} KB`);
|
|
1530
|
+
}
|
|
1531
|
+
else {
|
|
1532
|
+
console.log("⏭️ 视频生成失败或未完成");
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
catch (error) {
|
|
1536
|
+
if (error.message?.includes("已轮询") || error.message?.includes("仍未完成")) {
|
|
1537
|
+
console.log("⏭️ 轮询超时(正常,视频生成需要较长时间)");
|
|
1538
|
+
}
|
|
1539
|
+
else {
|
|
1540
|
+
throw error;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
}, 240000);
|
|
1151
1544
|
});
|
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.1.
|
|
12
|
+
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.1.2";
|
|
13
13
|
/**
|
|
14
14
|
* 版本兼容性错误
|
|
15
15
|
*/
|
|
@@ -24,8 +24,8 @@ declare class SDKConfig {
|
|
|
24
24
|
private _pluginId;
|
|
25
25
|
private _versionCompatible;
|
|
26
26
|
private _versionCheckPromise;
|
|
27
|
-
readonly sdkSignature = "AI_WORLD_SDK_V:1.1.
|
|
28
|
-
readonly sdkVersion = "1.1.
|
|
27
|
+
readonly sdkSignature = "AI_WORLD_SDK_V:1.1.2";
|
|
28
|
+
readonly sdkVersion = "1.1.2";
|
|
29
29
|
constructor();
|
|
30
30
|
/**
|
|
31
31
|
* 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.1.
|
|
10
|
+
const SDK_VERSION = "1.1.2";
|
|
11
11
|
/**
|
|
12
12
|
* SDK 特征码 - 用于在构建后的 JS 文件中识别 SDK 版本
|
|
13
13
|
* 格式: AI_WORLD_SDK_V:版本号
|
|
@@ -15,7 +15,7 @@ const SDK_VERSION = "1.1.1";
|
|
|
15
15
|
*
|
|
16
16
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
17
17
|
*/
|
|
18
|
-
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.1.
|
|
18
|
+
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.1.2";
|
|
19
19
|
/**
|
|
20
20
|
* 版本兼容性错误
|
|
21
21
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { BaseChatModel, BaseChatModelParams } from "./base";
|
|
|
8
8
|
import { DoubaoImageGenerationClient, DoubaoImageSize, type DoubaoImageGenerationConfig, type DoubaoImageGenerationRequest, type DoubaoImageGenerationResponse } from "./doubao-image-generation";
|
|
9
9
|
import { GeminiImageGenerationClient, type GeminiImageGenerationConfig, type GeminiImageGenerationRequest, type GeminiImageGenerationResponse } from "./gemini-image-generation";
|
|
10
10
|
import { VideoGenerationClient, type VideoGenerationConfig, type VideoGenerationRequest, type ContentGenerationTaskID, type ContentGenerationTask } from "./video_generation";
|
|
11
|
+
import { OpenAIVideoGenerationClient, type OpenAIVideoGenerationConfig, type OpenAIVideoGenerationRequest, type OpenAIVideoTaskResponse } from "./openai_video_generation";
|
|
11
12
|
import { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions } from "./download";
|
|
12
13
|
import { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo } from "./auth";
|
|
13
14
|
export { BaseMessage, HumanMessage, AIMessage, SystemMessage, AIMessageChunk, type MessageContent, type AIMessageChunkData, } from "./messages";
|
|
@@ -23,6 +24,7 @@ export interface LangchainClientConfig {
|
|
|
23
24
|
export { DoubaoImageGenerationClient, type DoubaoImageGenerationConfig, type DoubaoImageGenerationRequest, type DoubaoImageGenerationResponse, type DoubaoImageSize, };
|
|
24
25
|
export { GeminiImageGenerationClient, type GeminiImageGenerationConfig, type GeminiImageGenerationRequest, type GeminiImageGenerationResponse, };
|
|
25
26
|
export { VideoGenerationClient, type VideoGenerationConfig, type VideoGenerationRequest, type ContentGenerationTaskID, type ContentGenerationTask, };
|
|
27
|
+
export { OpenAIVideoGenerationClient, type OpenAIVideoGenerationConfig, type OpenAIVideoGenerationRequest, type OpenAIVideoTaskResponse, };
|
|
26
28
|
export { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions, };
|
|
27
29
|
export { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo, };
|
|
28
30
|
export { sdkConfig, VersionCompatibilityError, SDK_SIGNATURE } from "./config";
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @see https://github.com/langchain-ai/langchainjs
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.SDK_SIGNATURE = exports.VersionCompatibilityError = exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.DownloadClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
|
|
9
|
+
exports.SDK_SIGNATURE = exports.VersionCompatibilityError = exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.DownloadClient = exports.OpenAIVideoGenerationClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
|
|
10
10
|
exports.createChatModel = createChatModel;
|
|
11
11
|
const openai_1 = require("./chat_models/openai");
|
|
12
12
|
const google_1 = require("./chat_models/google");
|
|
@@ -16,6 +16,8 @@ const gemini_image_generation_1 = require("./gemini-image-generation");
|
|
|
16
16
|
Object.defineProperty(exports, "GeminiImageGenerationClient", { enumerable: true, get: function () { return gemini_image_generation_1.GeminiImageGenerationClient; } });
|
|
17
17
|
const video_generation_1 = require("./video_generation");
|
|
18
18
|
Object.defineProperty(exports, "VideoGenerationClient", { enumerable: true, get: function () { return video_generation_1.VideoGenerationClient; } });
|
|
19
|
+
const openai_video_generation_1 = require("./openai_video_generation");
|
|
20
|
+
Object.defineProperty(exports, "OpenAIVideoGenerationClient", { enumerable: true, get: function () { return openai_video_generation_1.OpenAIVideoGenerationClient; } });
|
|
19
21
|
const download_1 = require("./download");
|
|
20
22
|
Object.defineProperty(exports, "DownloadClient", { enumerable: true, get: function () { return download_1.DownloadClient; } });
|
|
21
23
|
const auth_1 = require("./auth");
|
package/dist/log.js
CHANGED
|
@@ -27,7 +27,7 @@ function logRequest(method, url, headers, body) {
|
|
|
27
27
|
debugLog("📤 HTTP Request");
|
|
28
28
|
debugLog(" Method:", method);
|
|
29
29
|
debugLog(" URL:", url);
|
|
30
|
-
debugLog(" Headers:", { ...headers, Authorization: headers?.Authorization
|
|
30
|
+
debugLog(" Headers:", { ...headers, Authorization: headers?.Authorization });
|
|
31
31
|
if (body) {
|
|
32
32
|
try {
|
|
33
33
|
const bodyStr = typeof body === "string" ? body : JSON.stringify(body, null, 2);
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Video Generation Client
|
|
3
|
+
* OpenAI 视频生成客户端
|
|
4
|
+
*/
|
|
5
|
+
export interface OpenAIVideoGenerationConfig {
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
token?: string;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export interface OpenAIVideoGenerationRequest {
|
|
11
|
+
prompt: string;
|
|
12
|
+
model?: string;
|
|
13
|
+
provider?: "aihubmix" | "api2img";
|
|
14
|
+
seconds?: "4" | "8" | "12";
|
|
15
|
+
size?: "720x1280" | "1280x720" | "1024x1792" | "1792x1024";
|
|
16
|
+
input_reference?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OpenAIVideoTaskResponse {
|
|
19
|
+
id: string;
|
|
20
|
+
object?: string;
|
|
21
|
+
status: "queued" | "in_progress" | "completed" | "failed";
|
|
22
|
+
created_at: number;
|
|
23
|
+
model?: string;
|
|
24
|
+
prompt?: string;
|
|
25
|
+
seconds?: "4" | "8" | "12";
|
|
26
|
+
size?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
error?: Record<string, any>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* OpenAI Video Generation Client
|
|
32
|
+
* OpenAI 视频生成客户端
|
|
33
|
+
*
|
|
34
|
+
* 使用示例:
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { OpenAIVideoGenerationClient } from 'ai-world-sdk';
|
|
37
|
+
*
|
|
38
|
+
* const client = new OpenAIVideoGenerationClient({
|
|
39
|
+
* baseUrl: 'http://localhost:8000',
|
|
40
|
+
* token: 'your-auth-token'
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // 生成视频
|
|
44
|
+
* const task = await client.generate({
|
|
45
|
+
* prompt: 'A beautiful sunset over the ocean',
|
|
46
|
+
* model: 'sora-2',
|
|
47
|
+
* provider: 'aihubmix',
|
|
48
|
+
* seconds: '4',
|
|
49
|
+
* size: '1280x720'
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* console.log('Task ID:', task.id);
|
|
53
|
+
*
|
|
54
|
+
* // 查询任务状态
|
|
55
|
+
* const status = await client.getTask(task.id);
|
|
56
|
+
* console.log('Status:', status.status);
|
|
57
|
+
* if (status.video_url) {
|
|
58
|
+
* console.log('Video URL:', status.video_url);
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare class OpenAIVideoGenerationClient {
|
|
63
|
+
private headers;
|
|
64
|
+
constructor(config?: OpenAIVideoGenerationConfig);
|
|
65
|
+
/**
|
|
66
|
+
* 生成视频
|
|
67
|
+
* Generate video
|
|
68
|
+
*
|
|
69
|
+
* @param request - 视频生成请求参数
|
|
70
|
+
* @returns 任务响应,包含任务 ID
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // 文本生成视频
|
|
75
|
+
* const task = await client.generate({
|
|
76
|
+
* prompt: 'A beautiful sunset over the ocean with waves crashing on the shore',
|
|
77
|
+
* model: 'sora-2',
|
|
78
|
+
* provider: 'aihubmix',
|
|
79
|
+
* seconds: '4',
|
|
80
|
+
* size: '1280x720'
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* // 图像生成视频(使用 base64)
|
|
84
|
+
* const taskWithImage = await client.generate({
|
|
85
|
+
* prompt: 'Animate this image with gentle waves',
|
|
86
|
+
* input_reference: 'data:image/png;base64,iVBORw0KGgo...',
|
|
87
|
+
* model: 'sora-2',
|
|
88
|
+
* seconds: '4'
|
|
89
|
+
* });
|
|
90
|
+
* console.log('Task ID:', task.id);
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
generate(request: OpenAIVideoGenerationRequest): Promise<OpenAIVideoTaskResponse>;
|
|
94
|
+
/**
|
|
95
|
+
* 查询视频任务状态
|
|
96
|
+
* Get video task status
|
|
97
|
+
*
|
|
98
|
+
* @param taskId - 任务 ID
|
|
99
|
+
* @returns 任务状态信息
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const status = await client.getTask('vid_abc123');
|
|
104
|
+
* console.log('Status:', status.status);
|
|
105
|
+
* if (status.status === 'completed' && status.url) {
|
|
106
|
+
* console.log('Video URL:', status.url);
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
getTask(taskId: string, provider: "aihubmix" | "api2img"): Promise<OpenAIVideoTaskResponse>;
|
|
111
|
+
/**
|
|
112
|
+
* 轮询等待任务完成
|
|
113
|
+
* Poll and wait for task completion
|
|
114
|
+
*
|
|
115
|
+
* @param taskId - 任务 ID
|
|
116
|
+
* @param options - 轮询选项
|
|
117
|
+
* @returns 完成的任务信息
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const result = await client.waitForCompletion('vid_abc123', {
|
|
122
|
+
* maxAttempts: 60,
|
|
123
|
+
* interval: 5000
|
|
124
|
+
* });
|
|
125
|
+
* console.log('Video URL:', result.url);
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
waitForCompletion(taskId: string, provider?: "aihubmix" | "api2img", options?: {
|
|
129
|
+
maxAttempts?: number;
|
|
130
|
+
interval?: number;
|
|
131
|
+
onProgress?: (status: OpenAIVideoTaskResponse) => void;
|
|
132
|
+
}): Promise<OpenAIVideoTaskResponse>;
|
|
133
|
+
/**
|
|
134
|
+
* 生成视频并等待完成
|
|
135
|
+
* Generate video and wait for completion
|
|
136
|
+
*
|
|
137
|
+
* @param request - 视频生成请求参数
|
|
138
|
+
* @param options - 轮询选项
|
|
139
|
+
* @returns 完成的任务信息,包含视频 URL
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const result = await client.generateAndWait({
|
|
144
|
+
* prompt: 'A beautiful sunset',
|
|
145
|
+
* model: 'sora-2',
|
|
146
|
+
* provider: 'aihubmix',
|
|
147
|
+
* seconds: '4'
|
|
148
|
+
* }, {
|
|
149
|
+
* onProgress: (status) => {
|
|
150
|
+
* console.log('Status:', status.status);
|
|
151
|
+
* }
|
|
152
|
+
* });
|
|
153
|
+
* console.log('Video URL:', result.video_url);
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
generateAndWait(request: OpenAIVideoGenerationRequest, options?: {
|
|
157
|
+
maxAttempts?: number;
|
|
158
|
+
interval?: number;
|
|
159
|
+
onProgress?: (status: OpenAIVideoTaskResponse) => void;
|
|
160
|
+
}): Promise<OpenAIVideoTaskResponse>;
|
|
161
|
+
/**
|
|
162
|
+
* 下载视频文件
|
|
163
|
+
* Download video file
|
|
164
|
+
*
|
|
165
|
+
* @param taskId - 视频任务 ID
|
|
166
|
+
* @param provider - 提供商类型 (aihubmix, api2img)
|
|
167
|
+
* @param variant - 下载类型 (video, thumbnail),默认: video
|
|
168
|
+
* @returns Blob 对象(可用于下载或显示)
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // 下载视频
|
|
173
|
+
* const videoBlob = await client.downloadVideo('vid_abc123', 'aihubmix', 'video');
|
|
174
|
+
*
|
|
175
|
+
* // 在浏览器中创建下载链接
|
|
176
|
+
* const url = URL.createObjectURL(videoBlob);
|
|
177
|
+
* const a = document.createElement('a');
|
|
178
|
+
* a.href = url;
|
|
179
|
+
* a.download = 'video.mp4';
|
|
180
|
+
* a.click();
|
|
181
|
+
* URL.revokeObjectURL(url);
|
|
182
|
+
*
|
|
183
|
+
* // 或下载缩略图
|
|
184
|
+
* const thumbnail = await client.downloadVideo('vid_abc123', 'aihubmix', 'thumbnail');
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
downloadVideo(taskId: string, provider?: "aihubmix" | "api2img", variant?: "video" | "thumbnail"): Promise<Blob>;
|
|
188
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Video Generation Client
|
|
4
|
+
* OpenAI 视频生成客户端
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.OpenAIVideoGenerationClient = void 0;
|
|
8
|
+
const config_1 = require("./config");
|
|
9
|
+
const log_1 = require("./log");
|
|
10
|
+
/**
|
|
11
|
+
* OpenAI Video Generation Client
|
|
12
|
+
* OpenAI 视频生成客户端
|
|
13
|
+
*
|
|
14
|
+
* 使用示例:
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { OpenAIVideoGenerationClient } from 'ai-world-sdk';
|
|
17
|
+
*
|
|
18
|
+
* const client = new OpenAIVideoGenerationClient({
|
|
19
|
+
* baseUrl: 'http://localhost:8000',
|
|
20
|
+
* token: 'your-auth-token'
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // 生成视频
|
|
24
|
+
* const task = await client.generate({
|
|
25
|
+
* prompt: 'A beautiful sunset over the ocean',
|
|
26
|
+
* model: 'sora-2',
|
|
27
|
+
* provider: 'aihubmix',
|
|
28
|
+
* seconds: '4',
|
|
29
|
+
* size: '1280x720'
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* console.log('Task ID:', task.id);
|
|
33
|
+
*
|
|
34
|
+
* // 查询任务状态
|
|
35
|
+
* const status = await client.getTask(task.id);
|
|
36
|
+
* console.log('Status:', status.status);
|
|
37
|
+
* if (status.video_url) {
|
|
38
|
+
* console.log('Video URL:', status.video_url);
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
class OpenAIVideoGenerationClient {
|
|
43
|
+
constructor(config = {}) {
|
|
44
|
+
const globalHeaders = config_1.sdkConfig.getHeaders();
|
|
45
|
+
this.headers = {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
"Authorization": `Bearer ${config_1.sdkConfig.getToken()}`,
|
|
48
|
+
"X-Base-Url": config?.baseUrl || "",
|
|
49
|
+
...globalHeaders,
|
|
50
|
+
...config?.headers,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 生成视频
|
|
55
|
+
* Generate video
|
|
56
|
+
*
|
|
57
|
+
* @param request - 视频生成请求参数
|
|
58
|
+
* @returns 任务响应,包含任务 ID
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* // 文本生成视频
|
|
63
|
+
* const task = await client.generate({
|
|
64
|
+
* prompt: 'A beautiful sunset over the ocean with waves crashing on the shore',
|
|
65
|
+
* model: 'sora-2',
|
|
66
|
+
* provider: 'aihubmix',
|
|
67
|
+
* seconds: '4',
|
|
68
|
+
* size: '1280x720'
|
|
69
|
+
* });
|
|
70
|
+
*
|
|
71
|
+
* // 图像生成视频(使用 base64)
|
|
72
|
+
* const taskWithImage = await client.generate({
|
|
73
|
+
* prompt: 'Animate this image with gentle waves',
|
|
74
|
+
* input_reference: 'data:image/png;base64,iVBORw0KGgo...',
|
|
75
|
+
* model: 'sora-2',
|
|
76
|
+
* seconds: '4'
|
|
77
|
+
* });
|
|
78
|
+
* console.log('Task ID:', task.id);
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
async generate(request) {
|
|
82
|
+
const url = `${config_1.sdkConfig.getServerUrl()}/api/openai-video-proxy/generate`;
|
|
83
|
+
// 记录请求日志
|
|
84
|
+
(0, log_1.logRequest)("POST", url, this.headers, request);
|
|
85
|
+
try {
|
|
86
|
+
const response = await fetch(url, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers: this.headers,
|
|
89
|
+
body: JSON.stringify(request),
|
|
90
|
+
});
|
|
91
|
+
// 记录响应日志
|
|
92
|
+
(0, log_1.logResponse)(response.status, response.statusText, response.headers, response.body);
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
const errorData = await response.json().catch(() => ({
|
|
95
|
+
detail: response.statusText,
|
|
96
|
+
}));
|
|
97
|
+
// 检查版本兼容性错误
|
|
98
|
+
if (response.status === 400 &&
|
|
99
|
+
errorData.detail?.includes("version")) {
|
|
100
|
+
throw new config_1.VersionCompatibilityError(errorData.detail);
|
|
101
|
+
}
|
|
102
|
+
throw new Error(errorData.detail || `HTTP error! status: ${response.status}`);
|
|
103
|
+
}
|
|
104
|
+
const data = await response.json();
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error instanceof config_1.VersionCompatibilityError) {
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`OpenAI 视频生成失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* 查询视频任务状态
|
|
116
|
+
* Get video task status
|
|
117
|
+
*
|
|
118
|
+
* @param taskId - 任务 ID
|
|
119
|
+
* @returns 任务状态信息
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const status = await client.getTask('vid_abc123');
|
|
124
|
+
* console.log('Status:', status.status);
|
|
125
|
+
* if (status.status === 'completed' && status.url) {
|
|
126
|
+
* console.log('Video URL:', status.url);
|
|
127
|
+
* }
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
async getTask(taskId, provider) {
|
|
131
|
+
const url = `${config_1.sdkConfig.getServerUrl()}/api/openai-video-proxy/${taskId}?provider=${provider}`;
|
|
132
|
+
// 记录请求日志
|
|
133
|
+
(0, log_1.logRequest)("GET", url, this.headers, {});
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(url, {
|
|
136
|
+
method: "GET",
|
|
137
|
+
headers: this.headers,
|
|
138
|
+
});
|
|
139
|
+
// 记录响应日志
|
|
140
|
+
(0, log_1.logResponse)(response.status, response.statusText, response.headers, response.body);
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
const errorData = await response.json().catch(() => ({
|
|
143
|
+
detail: response.statusText,
|
|
144
|
+
}));
|
|
145
|
+
// 检查版本兼容性错误
|
|
146
|
+
if (response.status === 400 &&
|
|
147
|
+
errorData.detail?.includes("version")) {
|
|
148
|
+
throw new config_1.VersionCompatibilityError(errorData.detail);
|
|
149
|
+
}
|
|
150
|
+
throw new Error(errorData.detail || `HTTP error! status: ${response.status}`);
|
|
151
|
+
}
|
|
152
|
+
const data = await response.json();
|
|
153
|
+
return data;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error instanceof config_1.VersionCompatibilityError) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
throw new Error(`查询任务失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 轮询等待任务完成
|
|
164
|
+
* Poll and wait for task completion
|
|
165
|
+
*
|
|
166
|
+
* @param taskId - 任务 ID
|
|
167
|
+
* @param options - 轮询选项
|
|
168
|
+
* @returns 完成的任务信息
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* const result = await client.waitForCompletion('vid_abc123', {
|
|
173
|
+
* maxAttempts: 60,
|
|
174
|
+
* interval: 5000
|
|
175
|
+
* });
|
|
176
|
+
* console.log('Video URL:', result.url);
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
async waitForCompletion(taskId, provider = "aihubmix", options = {}) {
|
|
180
|
+
const { maxAttempts = 60, interval = 5000, onProgress } = options;
|
|
181
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
182
|
+
const task = await this.getTask(taskId, provider || "aihubmix");
|
|
183
|
+
if (onProgress) {
|
|
184
|
+
onProgress(task);
|
|
185
|
+
}
|
|
186
|
+
if (task.status === "completed") {
|
|
187
|
+
return task;
|
|
188
|
+
}
|
|
189
|
+
if (task.status === "failed") {
|
|
190
|
+
throw new Error(`任务失败: ${task.error || "未知错误"}`);
|
|
191
|
+
}
|
|
192
|
+
// 等待指定时间后继续轮询
|
|
193
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
194
|
+
}
|
|
195
|
+
throw new Error(`任务超时: 已轮询 ${maxAttempts} 次,任务仍未完成`);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 生成视频并等待完成
|
|
199
|
+
* Generate video and wait for completion
|
|
200
|
+
*
|
|
201
|
+
* @param request - 视频生成请求参数
|
|
202
|
+
* @param options - 轮询选项
|
|
203
|
+
* @returns 完成的任务信息,包含视频 URL
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const result = await client.generateAndWait({
|
|
208
|
+
* prompt: 'A beautiful sunset',
|
|
209
|
+
* model: 'sora-2',
|
|
210
|
+
* provider: 'aihubmix',
|
|
211
|
+
* seconds: '4'
|
|
212
|
+
* }, {
|
|
213
|
+
* onProgress: (status) => {
|
|
214
|
+
* console.log('Status:', status.status);
|
|
215
|
+
* }
|
|
216
|
+
* });
|
|
217
|
+
* console.log('Video URL:', result.video_url);
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
async generateAndWait(request, options) {
|
|
221
|
+
const task = await this.generate(request);
|
|
222
|
+
return this.waitForCompletion(task.id, request.provider || "aihubmix", options);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 下载视频文件
|
|
226
|
+
* Download video file
|
|
227
|
+
*
|
|
228
|
+
* @param taskId - 视频任务 ID
|
|
229
|
+
* @param provider - 提供商类型 (aihubmix, api2img)
|
|
230
|
+
* @param variant - 下载类型 (video, thumbnail),默认: video
|
|
231
|
+
* @returns Blob 对象(可用于下载或显示)
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* // 下载视频
|
|
236
|
+
* const videoBlob = await client.downloadVideo('vid_abc123', 'aihubmix', 'video');
|
|
237
|
+
*
|
|
238
|
+
* // 在浏览器中创建下载链接
|
|
239
|
+
* const url = URL.createObjectURL(videoBlob);
|
|
240
|
+
* const a = document.createElement('a');
|
|
241
|
+
* a.href = url;
|
|
242
|
+
* a.download = 'video.mp4';
|
|
243
|
+
* a.click();
|
|
244
|
+
* URL.revokeObjectURL(url);
|
|
245
|
+
*
|
|
246
|
+
* // 或下载缩略图
|
|
247
|
+
* const thumbnail = await client.downloadVideo('vid_abc123', 'aihubmix', 'thumbnail');
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
async downloadVideo(taskId, provider = "aihubmix", variant = "video") {
|
|
251
|
+
const url = `${config_1.sdkConfig.getServerUrl()}/api/openai-video-proxy/${taskId}/download?provider=${provider}&variant=${variant}`;
|
|
252
|
+
// 记录请求日志
|
|
253
|
+
(0, log_1.logRequest)("GET", url, this.headers, { taskId, provider, variant });
|
|
254
|
+
try {
|
|
255
|
+
const response = await fetch(url, {
|
|
256
|
+
method: "GET",
|
|
257
|
+
headers: this.headers,
|
|
258
|
+
});
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
const errorData = await response.json().catch(() => null);
|
|
261
|
+
// 记录错误响应日志
|
|
262
|
+
(0, log_1.logResponse)(response.status, response.statusText, response.headers, errorData);
|
|
263
|
+
// 检查版本兼容性错误
|
|
264
|
+
if (response.status === 400 &&
|
|
265
|
+
errorData?.detail?.includes("version")) {
|
|
266
|
+
throw new config_1.VersionCompatibilityError(errorData.detail);
|
|
267
|
+
}
|
|
268
|
+
throw new Error(errorData?.detail || `HTTP error! status: ${response.status}`);
|
|
269
|
+
}
|
|
270
|
+
// 流式下载视频(浏览器会自动处理流式传输)
|
|
271
|
+
const blob = await response.blob();
|
|
272
|
+
// 记录成功日志
|
|
273
|
+
(0, log_1.logResponse)(response.status, response.statusText, response.headers, {
|
|
274
|
+
blobSize: blob.size,
|
|
275
|
+
blobType: blob.type,
|
|
276
|
+
});
|
|
277
|
+
return blob;
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
if (error instanceof config_1.VersionCompatibilityError) {
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
throw new Error(`下载视频失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.OpenAIVideoGenerationClient = OpenAIVideoGenerationClient;
|
package/package.json
CHANGED