ai-world-sdk 1.0.0
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 +1006 -0
- package/dist/__tests__/example.test.d.ts +5 -0
- package/dist/__tests__/example.test.js +533 -0
- package/dist/base.d.ts +96 -0
- package/dist/base.js +181 -0
- package/dist/chat_models/anthropic.d.ts +11 -0
- package/dist/chat_models/anthropic.js +17 -0
- package/dist/chat_models/google.d.ts +11 -0
- package/dist/chat_models/google.js +17 -0
- package/dist/chat_models/openai.d.ts +11 -0
- package/dist/chat_models/openai.js +17 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.js +67 -0
- package/dist/image_generation.d.ts +38 -0
- package/dist/image_generation.js +70 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +77 -0
- package/dist/messages.d.ts +71 -0
- package/dist/messages.js +73 -0
- package/dist/video_generation.d.ts +91 -0
- package/dist/video_generation.js +88 -0
- package/package.json +56 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Test file for Langchain SDK
|
|
4
|
+
* Tests Gemini model functionality
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const dotenv = __importStar(require("dotenv"));
|
|
41
|
+
const index_1 = require("../index");
|
|
42
|
+
// Load environment variables from .env file
|
|
43
|
+
dotenv.config();
|
|
44
|
+
index_1.sdkConfig.setBaseUrl("http://localhost:8000");
|
|
45
|
+
index_1.sdkConfig.setToken(process.env.AUTH_TOKEN || process.env.TOKEN || "");
|
|
46
|
+
function extractTextFromChunk(chunk) {
|
|
47
|
+
if (typeof chunk.content === "string") {
|
|
48
|
+
return chunk.content;
|
|
49
|
+
}
|
|
50
|
+
else if (Array.isArray(chunk.content)) {
|
|
51
|
+
return chunk.content.map(item => typeof item === "string" ? item : item?.text || "").join("");
|
|
52
|
+
}
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
describe("Langchain SDK Tests", () => {
|
|
56
|
+
const token = process.env.AUTH_TOKEN || process.env.TOKEN;
|
|
57
|
+
beforeAll(() => {
|
|
58
|
+
if (!token) {
|
|
59
|
+
console.warn("⚠️ 警告: 未设置 AUTH_TOKEN 或 TOKEN 环境变量,测试可能会失败");
|
|
60
|
+
console.warn(" 请在项目根目录创建 .env 文件,添加: AUTH_TOKEN=your_jwt_token");
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
test("ChatGoogleGenerativeAI - 非流式调用", async () => {
|
|
64
|
+
if (!token) {
|
|
65
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
69
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
70
|
+
temperature: 0.7,
|
|
71
|
+
});
|
|
72
|
+
const response = await gemini.invoke([
|
|
73
|
+
new index_1.HumanMessage("你好,请用一句话介绍人工智能。"),
|
|
74
|
+
]);
|
|
75
|
+
expect(response).toBeDefined();
|
|
76
|
+
expect(response.content).toBeDefined();
|
|
77
|
+
expect(typeof response.content).toBe("string");
|
|
78
|
+
console.log("✅ 非流式测试成功");
|
|
79
|
+
console.log("AI:", response.content);
|
|
80
|
+
}, 30000);
|
|
81
|
+
test("ChatGoogleGenerativeAI - 流式调用", async () => {
|
|
82
|
+
if (!token) {
|
|
83
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
87
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
88
|
+
temperature: 0.7,
|
|
89
|
+
});
|
|
90
|
+
let fullText = "";
|
|
91
|
+
for await (const chunk of gemini.stream([
|
|
92
|
+
new index_1.HumanMessage("请用一句话介绍人工智能,然后解释它的重要性。"),
|
|
93
|
+
])) {
|
|
94
|
+
// chunk 是 AIMessageChunk 对象,提取 content
|
|
95
|
+
fullText += extractTextFromChunk(chunk);
|
|
96
|
+
console.log("AI stream chunk:", chunk);
|
|
97
|
+
console.log("AI stream text:", fullText);
|
|
98
|
+
}
|
|
99
|
+
expect(fullText.length).toBeGreaterThan(0);
|
|
100
|
+
console.log("✅ 流式测试成功");
|
|
101
|
+
console.log(`完整回复长度: ${fullText.length} 字符`);
|
|
102
|
+
}, 30000);
|
|
103
|
+
test("createChatModel 工厂函数", async () => {
|
|
104
|
+
if (!token) {
|
|
105
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const model = (0, index_1.createChatModel)("gemini-2.0-flash-exp-image-generation", {
|
|
109
|
+
temperature: 0.7,
|
|
110
|
+
});
|
|
111
|
+
const response = await model.invoke([
|
|
112
|
+
new index_1.SystemMessage("You are a helpful assistant."),
|
|
113
|
+
new index_1.HumanMessage("What is the capital of France?"),
|
|
114
|
+
]);
|
|
115
|
+
expect(response).toBeDefined();
|
|
116
|
+
expect(response.content).toBeDefined();
|
|
117
|
+
expect(typeof response.content).toBe("string");
|
|
118
|
+
console.log("✅ 工厂函数测试成功");
|
|
119
|
+
console.log("AI:", response.content);
|
|
120
|
+
}, 30000);
|
|
121
|
+
test("BaseChatModel - bind 方法", async () => {
|
|
122
|
+
if (!token) {
|
|
123
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
127
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
128
|
+
temperature: 0.5,
|
|
129
|
+
});
|
|
130
|
+
// 使用 bind 方法绑定新的参数
|
|
131
|
+
const boundModel = gemini.bind({ temperature: 0.9 });
|
|
132
|
+
const response = await boundModel.invoke([
|
|
133
|
+
new index_1.HumanMessage("用一句话介绍人工智能。"),
|
|
134
|
+
]);
|
|
135
|
+
expect(response).toBeDefined();
|
|
136
|
+
expect(response.content).toBeDefined();
|
|
137
|
+
console.log("✅ bind 方法测试成功");
|
|
138
|
+
console.log("AI:", response.content);
|
|
139
|
+
}, 30000);
|
|
140
|
+
test("BaseChatModel - batch 方法", async () => {
|
|
141
|
+
if (!token) {
|
|
142
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
146
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
147
|
+
temperature: 0.7,
|
|
148
|
+
});
|
|
149
|
+
// 批量调用
|
|
150
|
+
const responses = await gemini.batch([
|
|
151
|
+
[new index_1.HumanMessage("什么是人工智能?")],
|
|
152
|
+
[new index_1.HumanMessage("什么是机器学习?")],
|
|
153
|
+
[new index_1.HumanMessage("什么是深度学习?")],
|
|
154
|
+
]);
|
|
155
|
+
expect(responses).toBeDefined();
|
|
156
|
+
expect(Array.isArray(responses)).toBe(true);
|
|
157
|
+
expect(responses.length).toBe(3);
|
|
158
|
+
responses.forEach((response) => {
|
|
159
|
+
expect(response).toBeDefined();
|
|
160
|
+
expect(response.content).toBeDefined();
|
|
161
|
+
});
|
|
162
|
+
console.log("✅ batch 方法测试成功");
|
|
163
|
+
console.log(`批量响应数量: ${responses.length}`);
|
|
164
|
+
}, 30000);
|
|
165
|
+
test("ChatGoogleGenerativeAI - aihubmix.com no stream", async () => {
|
|
166
|
+
if (!token) {
|
|
167
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
171
|
+
baseUrl: "http://localhost:8000",
|
|
172
|
+
token: token || "",
|
|
173
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
174
|
+
temperature: 0.7,
|
|
175
|
+
headers: {
|
|
176
|
+
"X-Base-Url": "https://aihubmix.com",
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
const response = await gemini.invoke([
|
|
180
|
+
new index_1.HumanMessage("aihubmix.com是做什么的"),
|
|
181
|
+
]);
|
|
182
|
+
expect(response).toBeDefined();
|
|
183
|
+
expect(response.content).toBeDefined();
|
|
184
|
+
expect(typeof response.content).toBe("string");
|
|
185
|
+
console.log("✅ aihubmix.com no stream 测试成功");
|
|
186
|
+
console.log("AI:", response.content);
|
|
187
|
+
}, 30000);
|
|
188
|
+
test("ChatGoogleGenerativeAI - aihubmix.com stream", async () => {
|
|
189
|
+
if (!token) {
|
|
190
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
194
|
+
baseUrl: "http://localhost:8000",
|
|
195
|
+
token: token || "",
|
|
196
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
197
|
+
temperature: 0.7,
|
|
198
|
+
headers: {
|
|
199
|
+
"X-Base-Url": "https://aihubmix.com",
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
let fullText = "";
|
|
203
|
+
for await (const chunk of gemini.stream([
|
|
204
|
+
new index_1.HumanMessage("aihubmix.com是做什么的"),
|
|
205
|
+
])) {
|
|
206
|
+
fullText += extractTextFromChunk(chunk);
|
|
207
|
+
console.log("AI stream chunk:", chunk);
|
|
208
|
+
console.log("AI stream text:", fullText);
|
|
209
|
+
}
|
|
210
|
+
expect(fullText.length).toBeGreaterThan(0);
|
|
211
|
+
console.log("✅ aihubmix.com stream 测试成功");
|
|
212
|
+
console.log("AI:", fullText);
|
|
213
|
+
console.log(`完整回复长度: ${fullText.length} 字符`);
|
|
214
|
+
}, 30000);
|
|
215
|
+
test("ChatGoogleGenerativeAI - Google 图像生成", async () => {
|
|
216
|
+
if (!token) {
|
|
217
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
221
|
+
modelName: "gemini-2.0-flash-exp-image-generation",
|
|
222
|
+
temperature: 0.7,
|
|
223
|
+
});
|
|
224
|
+
const response = await gemini.invoke([
|
|
225
|
+
new index_1.HumanMessage("请生成一张展示人工智能概念的图片"),
|
|
226
|
+
]);
|
|
227
|
+
expect(response).toBeDefined();
|
|
228
|
+
expect(response.content).toBeDefined();
|
|
229
|
+
// 图像生成响应可能包含文本和图像数据
|
|
230
|
+
// 检查响应内容(可能是字符串、数组或包含图像的对象)
|
|
231
|
+
const content = response.content;
|
|
232
|
+
if (typeof content === "string") {
|
|
233
|
+
console.log("✅ Google 图像生成测试成功(文本响应)");
|
|
234
|
+
console.log("AI:", content);
|
|
235
|
+
}
|
|
236
|
+
else if (Array.isArray(content)) {
|
|
237
|
+
// 多模态响应,可能包含图像
|
|
238
|
+
const hasImage = content.some((item) => item?.type === "image_url" ||
|
|
239
|
+
item?.image_url ||
|
|
240
|
+
(typeof item === "string" && item.startsWith("data:image")));
|
|
241
|
+
console.log("✅ Google 图像生成测试成功(多模态响应)");
|
|
242
|
+
console.log("响应类型: 数组,包含图像:", hasImage);
|
|
243
|
+
console.log("响应内容:", JSON.stringify(content, null, 2));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.log("✅ Google 图像生成测试成功(其他格式)");
|
|
247
|
+
console.log("响应内容:", content);
|
|
248
|
+
}
|
|
249
|
+
}, 60000);
|
|
250
|
+
test("ChatGoogleGenerativeAI - aihubmix.com 图像生成", async () => {
|
|
251
|
+
if (!token) {
|
|
252
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
256
|
+
baseUrl: "http://localhost:8000",
|
|
257
|
+
token: token || "",
|
|
258
|
+
modelName: "gemini-3-pro-image-preview",
|
|
259
|
+
temperature: 0.7,
|
|
260
|
+
headers: {
|
|
261
|
+
"X-Base-Url": "https://aihubmix.com",
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
const response = await gemini.invoke([
|
|
265
|
+
new index_1.HumanMessage("请生成一张展示人工智能概念的图片"),
|
|
266
|
+
]);
|
|
267
|
+
expect(response).toBeDefined();
|
|
268
|
+
expect(response.content).toBeDefined();
|
|
269
|
+
// 图像生成响应可能包含文本和图像数据
|
|
270
|
+
// 检查响应内容(可能是字符串、数组或包含图像的对象)
|
|
271
|
+
const content = response.content;
|
|
272
|
+
if (typeof content === "string") {
|
|
273
|
+
console.log("✅ aihubmix.com 图像生成测试成功(文本响应)");
|
|
274
|
+
console.log("AI:", content);
|
|
275
|
+
}
|
|
276
|
+
else if (Array.isArray(content)) {
|
|
277
|
+
// 多模态响应,可能包含图像
|
|
278
|
+
const hasImage = content.some((item) => item?.type === "image_url" ||
|
|
279
|
+
item?.image_url ||
|
|
280
|
+
(typeof item === "string" && item.startsWith("data:image")));
|
|
281
|
+
console.log("✅ aihubmix.com 图像生成测试成功(多模态响应)");
|
|
282
|
+
console.log("响应类型: 数组,包含图像:", hasImage);
|
|
283
|
+
console.log("响应内容:", JSON.stringify(content, null, 2));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
console.log("✅ aihubmix.com 图像生成测试成功(其他格式)");
|
|
287
|
+
console.log("响应内容:", content);
|
|
288
|
+
}
|
|
289
|
+
}, 60000);
|
|
290
|
+
test("ChatGoogleGenerativeAI - seedream 图像生成", async () => {
|
|
291
|
+
if (!token) {
|
|
292
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const gemini = new index_1.ChatGoogleGenerativeAI({
|
|
296
|
+
baseUrl: "http://localhost:8000",
|
|
297
|
+
token: token || "",
|
|
298
|
+
modelName: "doubao-seedream-4-5-251128",
|
|
299
|
+
temperature: 0.7,
|
|
300
|
+
headers: {
|
|
301
|
+
"X-Base-Url": "https://ark.cn-beijing.volces.com/api/v3/images/generations",
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
const response = await gemini.invoke([
|
|
305
|
+
new index_1.HumanMessage("请生成一张展示人工智能概念的图片"),
|
|
306
|
+
]);
|
|
307
|
+
expect(response).toBeDefined();
|
|
308
|
+
expect(response.content).toBeDefined();
|
|
309
|
+
// 图像生成响应可能包含文本和图像数据
|
|
310
|
+
// 检查响应内容(可能是字符串、数组或包含图像的对象)
|
|
311
|
+
const content = response.content;
|
|
312
|
+
if (typeof content === "string") {
|
|
313
|
+
console.log("✅ aihubmix.com 图像生成测试成功(文本响应)");
|
|
314
|
+
console.log("AI:", content);
|
|
315
|
+
}
|
|
316
|
+
else if (Array.isArray(content)) {
|
|
317
|
+
// 多模态响应,可能包含图像
|
|
318
|
+
const hasImage = content.some((item) => item?.type === "image_url" ||
|
|
319
|
+
item?.image_url ||
|
|
320
|
+
(typeof item === "string" && item.startsWith("data:image")));
|
|
321
|
+
console.log("✅ aihubmix.com 图像生成测试成功(多模态响应)");
|
|
322
|
+
console.log("响应类型: 数组,包含图像:", hasImage);
|
|
323
|
+
console.log("响应内容:", JSON.stringify(content, null, 2));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
console.log("✅ aihubmix.com 图像生成测试成功(其他格式)");
|
|
327
|
+
console.log("响应内容:", content);
|
|
328
|
+
}
|
|
329
|
+
}, 60000);
|
|
330
|
+
test("ImageGenerationClient - 基础图像生成", async () => {
|
|
331
|
+
if (!token) {
|
|
332
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const imageClient = new index_1.ImageGenerationClient({});
|
|
336
|
+
const result = await imageClient.generate({
|
|
337
|
+
prompt: "充满活力的特写编辑肖像,模特眼神犀利,头戴雕塑感帽子,色彩拼接丰富,眼部焦点锐利,景深较浅,具有Vogue杂志封面的美学风格,采用中画幅拍摄,工作室灯光效果强烈。",
|
|
338
|
+
model: "doubao-seedream-4-5-251128",
|
|
339
|
+
size: "2K",
|
|
340
|
+
watermark: false,
|
|
341
|
+
n: 1,
|
|
342
|
+
});
|
|
343
|
+
expect(result).toBeDefined();
|
|
344
|
+
// 检查 OpenAI 标准格式:created 和 data
|
|
345
|
+
expect(result.created).toBeDefined();
|
|
346
|
+
expect(typeof result.created).toBe("number");
|
|
347
|
+
expect(result.data).toBeDefined();
|
|
348
|
+
expect(Array.isArray(result.data)).toBe(true);
|
|
349
|
+
expect(result.data.length).toBeGreaterThan(0);
|
|
350
|
+
// 检查每个图像数据项
|
|
351
|
+
result.data.forEach((item) => {
|
|
352
|
+
expect(item).toBeDefined();
|
|
353
|
+
// 应该包含 url 或 b64_json
|
|
354
|
+
expect(item.url || item.b64_json).toBeDefined();
|
|
355
|
+
});
|
|
356
|
+
console.log("✅ 基础图像生成测试成功");
|
|
357
|
+
console.log(`生成图像数量: ${result.data.length}`);
|
|
358
|
+
console.log("图像 URL:", result.data[0]?.url || "Base64 编码");
|
|
359
|
+
console.log("创建时间:", new Date(result.created * 1000).toISOString());
|
|
360
|
+
}, 120000);
|
|
361
|
+
test("ImageGenerationClient - 多图像生成 (n=2)", async () => {
|
|
362
|
+
if (!token) {
|
|
363
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const imageClient = new index_1.ImageGenerationClient({});
|
|
367
|
+
const result = await imageClient.generate({
|
|
368
|
+
prompt: "A beautiful sunset over the ocean with vibrant colors",
|
|
369
|
+
model: "doubao-seedream-4-5-251128",
|
|
370
|
+
size: "2K",
|
|
371
|
+
n: 2,
|
|
372
|
+
});
|
|
373
|
+
expect(result).toBeDefined();
|
|
374
|
+
expect(result.data).toBeDefined();
|
|
375
|
+
expect(Array.isArray(result.data)).toBe(true);
|
|
376
|
+
expect(result.data.length).toBe(2);
|
|
377
|
+
console.log("✅ 多图像生成测试成功");
|
|
378
|
+
console.log(`生成图像数量: ${result.data.length}`);
|
|
379
|
+
result.data.forEach((item, index) => {
|
|
380
|
+
console.log(`图像 ${index + 1}:`, item.url || "Base64 编码");
|
|
381
|
+
});
|
|
382
|
+
}, 120000);
|
|
383
|
+
test("ImageGenerationClient - 不同尺寸测试", async () => {
|
|
384
|
+
if (!token) {
|
|
385
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const imageClient = new index_1.ImageGenerationClient({});
|
|
389
|
+
const sizes = ["1K", "2K", "4K"];
|
|
390
|
+
for (const size of sizes) {
|
|
391
|
+
const result = await imageClient.generate({
|
|
392
|
+
prompt: "A futuristic city skyline at sunset",
|
|
393
|
+
model: "doubao-seedream-4-5-251128",
|
|
394
|
+
size: size,
|
|
395
|
+
n: 1,
|
|
396
|
+
});
|
|
397
|
+
expect(result).toBeDefined();
|
|
398
|
+
expect(result.data).toBeDefined();
|
|
399
|
+
expect(result.data.length).toBeGreaterThan(0);
|
|
400
|
+
console.log(`✅ 尺寸 ${size} 测试成功`);
|
|
401
|
+
}
|
|
402
|
+
}, 180000);
|
|
403
|
+
test("VideoGenerationClient - 创建视频生成任务(文本)", async () => {
|
|
404
|
+
if (!token) {
|
|
405
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const videoClient = new index_1.VideoGenerationClient({});
|
|
409
|
+
const task = await videoClient.create({
|
|
410
|
+
prompt: "A beautiful sunset over the ocean with waves crashing on the shore",
|
|
411
|
+
model: "doubao-seedance-1-0-pro-fast-251015",
|
|
412
|
+
duration: 5,
|
|
413
|
+
aspect_ratio: "16:9",
|
|
414
|
+
resolution: "720p",
|
|
415
|
+
});
|
|
416
|
+
expect(task).toBeDefined();
|
|
417
|
+
expect(task.id).toBeDefined();
|
|
418
|
+
expect(typeof task.id).toBe("string");
|
|
419
|
+
console.log("✅ 视频生成任务创建成功");
|
|
420
|
+
console.log("任务 ID:", task.id);
|
|
421
|
+
}, 30000);
|
|
422
|
+
test("VideoGenerationClient - 创建视频生成任务(图像)", async () => {
|
|
423
|
+
if (!token) {
|
|
424
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const videoClient = new index_1.VideoGenerationClient({});
|
|
428
|
+
const task = await videoClient.create({
|
|
429
|
+
image_url: "https://example.com/image.jpg",
|
|
430
|
+
model: "doubao-seedance-1-0-pro-fast-251015",
|
|
431
|
+
duration: 5,
|
|
432
|
+
});
|
|
433
|
+
expect(task).toBeDefined();
|
|
434
|
+
expect(task.id).toBeDefined();
|
|
435
|
+
expect(typeof task.id).toBe("string");
|
|
436
|
+
console.log("✅ 图像生成视频任务创建成功");
|
|
437
|
+
console.log("任务 ID:", task.id);
|
|
438
|
+
}, 30000);
|
|
439
|
+
test("VideoGenerationClient - 查询视频生成任务", async () => {
|
|
440
|
+
if (!token) {
|
|
441
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const videoClient = new index_1.VideoGenerationClient({
|
|
445
|
+
baseUrl: "http://localhost:8000",
|
|
446
|
+
token: token || "",
|
|
447
|
+
});
|
|
448
|
+
// 先创建一个任务
|
|
449
|
+
const createTask = await videoClient.create({
|
|
450
|
+
prompt: "A serene mountain landscape with a lake",
|
|
451
|
+
model: "doubao-seedance-1-0-pro-fast-251015",
|
|
452
|
+
duration: 3,
|
|
453
|
+
});
|
|
454
|
+
expect(createTask.id).toBeDefined();
|
|
455
|
+
// 查询任务状态
|
|
456
|
+
const task = await videoClient.get(createTask.id);
|
|
457
|
+
expect(task).toBeDefined();
|
|
458
|
+
expect(task.id).toBe(createTask.id);
|
|
459
|
+
expect(task.model).toBeDefined();
|
|
460
|
+
expect(task.status).toBeDefined();
|
|
461
|
+
expect(["queued", "running", "succeeded", "failed", "cancelled"]).toContain(task.status);
|
|
462
|
+
expect(task.created_at).toBeDefined();
|
|
463
|
+
expect(typeof task.created_at).toBe("number");
|
|
464
|
+
console.log("✅ 视频任务查询成功");
|
|
465
|
+
console.log("任务状态:", task.status);
|
|
466
|
+
console.log("任务模型:", task.model);
|
|
467
|
+
if (task.content?.video_url) {
|
|
468
|
+
console.log("视频 URL:", task.content.video_url);
|
|
469
|
+
}
|
|
470
|
+
}, 30000);
|
|
471
|
+
test("VideoGenerationClient - 轮询视频生成任务", async () => {
|
|
472
|
+
if (!token) {
|
|
473
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const videoClient = new index_1.VideoGenerationClient({});
|
|
477
|
+
// 创建任务
|
|
478
|
+
const createTask = await videoClient.create({
|
|
479
|
+
prompt: "A short video of a cat playing",
|
|
480
|
+
model: "doubao-seedance-1-0-pro-fast-251015",
|
|
481
|
+
duration: 3,
|
|
482
|
+
});
|
|
483
|
+
expect(createTask.id).toBeDefined();
|
|
484
|
+
console.log("createTask:", createTask.id);
|
|
485
|
+
// 轮询任务(使用较短的超时时间用于测试)
|
|
486
|
+
try {
|
|
487
|
+
const result = await videoClient.poll(createTask.id, {
|
|
488
|
+
interval: 2000, // 2秒轮询一次
|
|
489
|
+
timeout: 60000, // 60秒超时
|
|
490
|
+
});
|
|
491
|
+
expect(result).toBeDefined();
|
|
492
|
+
expect(["succeeded", "failed", "cancelled"]).toContain(result.status);
|
|
493
|
+
console.log("✅ 视频任务轮询完成");
|
|
494
|
+
console.log("最终状态:", result.status);
|
|
495
|
+
if (result.status === "succeeded" && result.content?.video_url) {
|
|
496
|
+
console.log("视频 URL:", result.content.video_url);
|
|
497
|
+
}
|
|
498
|
+
else if (result.error) {
|
|
499
|
+
console.log("错误信息:", result.error.message);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch (error) {
|
|
503
|
+
// 如果超时,这是正常的(视频生成需要时间)
|
|
504
|
+
if (error.message?.includes("timeout")) {
|
|
505
|
+
console.log("⏭️ 轮询超时(正常,视频生成需要较长时间)");
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
throw error;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}, 120000);
|
|
512
|
+
test("VideoGenerationClient - 直接提供 content", async () => {
|
|
513
|
+
if (!token) {
|
|
514
|
+
console.log("⏭️ 跳过测试: 未设置 AUTH_TOKEN");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const videoClient = new index_1.VideoGenerationClient({});
|
|
518
|
+
const task = await videoClient.create({
|
|
519
|
+
model: "doubao-seedance-1-0-pro-fast-251015",
|
|
520
|
+
content: [
|
|
521
|
+
{
|
|
522
|
+
type: "text",
|
|
523
|
+
text: "A beautiful sunset over the ocean --ratio 16:9 --duration 5",
|
|
524
|
+
},
|
|
525
|
+
],
|
|
526
|
+
return_last_frame: true,
|
|
527
|
+
});
|
|
528
|
+
expect(task).toBeDefined();
|
|
529
|
+
expect(task.id).toBeDefined();
|
|
530
|
+
console.log("✅ 使用 content 参数创建任务成功");
|
|
531
|
+
console.log("任务 ID:", task.id);
|
|
532
|
+
}, 30000);
|
|
533
|
+
});
|
package/dist/base.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base chat model class
|
|
3
|
+
* Similar to LangChain.js BaseChatModel
|
|
4
|
+
*/
|
|
5
|
+
import { BaseMessage, AIMessage, AIMessageChunk } from "./messages";
|
|
6
|
+
export interface BaseChatModelParams {
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
token?: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
temperature?: number;
|
|
11
|
+
maxTokens?: number;
|
|
12
|
+
topP?: number;
|
|
13
|
+
modelName?: string;
|
|
14
|
+
provider?: string;
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ChatResult {
|
|
18
|
+
content: string;
|
|
19
|
+
role: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ToolDefinition {
|
|
22
|
+
type: "function";
|
|
23
|
+
function: {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
parameters?: Record<string, any>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface BindOptions {
|
|
30
|
+
temperature?: number;
|
|
31
|
+
maxTokens?: number;
|
|
32
|
+
topP?: number;
|
|
33
|
+
tools?: ToolDefinition[];
|
|
34
|
+
toolChoice?: "auto" | "none" | "required" | {
|
|
35
|
+
type: "function";
|
|
36
|
+
function: {
|
|
37
|
+
name: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export declare abstract class BaseChatModel {
|
|
42
|
+
protected baseUrl: string;
|
|
43
|
+
protected headers: Record<string, string>;
|
|
44
|
+
protected temperature: number;
|
|
45
|
+
protected maxTokens?: number;
|
|
46
|
+
protected topP?: number;
|
|
47
|
+
protected modelName: string;
|
|
48
|
+
protected boundOptions?: BindOptions;
|
|
49
|
+
protected provider?: string;
|
|
50
|
+
protected apiKey?: string;
|
|
51
|
+
constructor(config: {
|
|
52
|
+
baseUrl?: string;
|
|
53
|
+
token?: string;
|
|
54
|
+
headers?: Record<string, string>;
|
|
55
|
+
temperature?: number;
|
|
56
|
+
maxTokens?: number;
|
|
57
|
+
topP?: number;
|
|
58
|
+
modelName: string;
|
|
59
|
+
provider?: string;
|
|
60
|
+
apiKey?: string;
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Invoke the model with messages (non-streaming)
|
|
64
|
+
* 遵循标准 LangChain API
|
|
65
|
+
*/
|
|
66
|
+
invoke(messages: BaseMessage[]): Promise<AIMessage>;
|
|
67
|
+
/**
|
|
68
|
+
* Stream the model with messages
|
|
69
|
+
* 遵循标准 LangChain API,返回 AIMessageChunk
|
|
70
|
+
*/
|
|
71
|
+
stream(messages: BaseMessage[]): AsyncGenerator<AIMessageChunk, void, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Batch invoke multiple message sets
|
|
74
|
+
* 遵循标准 LangChain API
|
|
75
|
+
*/
|
|
76
|
+
batch(messagesList: BaseMessage[][]): Promise<AIMessage[]>;
|
|
77
|
+
/**
|
|
78
|
+
* Bind options to the model (temperature, maxTokens, tools, etc.)
|
|
79
|
+
* Returns a new model instance with bound options
|
|
80
|
+
* Similar to LangChain.js bind method
|
|
81
|
+
*/
|
|
82
|
+
bind(options: BindOptions): BaseChatModel;
|
|
83
|
+
/**
|
|
84
|
+
* Bind tools to the model
|
|
85
|
+
* Similar to LangChain.js bindTools method
|
|
86
|
+
*/
|
|
87
|
+
bindTools(tools: ToolDefinition[]): BaseChatModel;
|
|
88
|
+
/**
|
|
89
|
+
* Merge bound options with provided options
|
|
90
|
+
*/
|
|
91
|
+
protected _mergeOptions(options: Partial<BindOptions>): BindOptions;
|
|
92
|
+
/**
|
|
93
|
+
* Get the current model name
|
|
94
|
+
*/
|
|
95
|
+
getModelName(): string;
|
|
96
|
+
}
|