@kevisual/ai 0.0.18 → 0.0.20
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/ai-provider-browser.d.ts +176 -18
- package/dist/ai-provider-browser.js +2301 -1620
- package/dist/ai-provider.d.ts +176 -18
- package/dist/ai-provider.js +27 -21
- package/package.json +15 -14
- package/src/jimeng/core.ts +113 -43
- package/src/provider/chat-adapter/mimo.ts +10 -0
- package/src/provider/chat-adapter/ollama.ts +0 -5
- package/src/provider/chat-adapter/siliconflow.ts +0 -5
- package/src/provider/core/chat.ts +42 -15
- package/src/provider/core/type.ts +166 -10
- package/src/provider/media/video/siliconflow.ts +6 -6
- package/src/test/aliyun/test.ts +0 -59
- package/src/test/chunks/01-get.ts +0 -65
- package/src/test/common.ts +0 -18
- package/src/test/encrypt/index.ts +0 -9
- package/src/test/func-call/curl.sh +0 -35
- package/src/test/func-call/demo.ts +0 -116
- package/src/test/model-scope/index.ts +0 -26
- package/src/test/ollama-knowledge.ts +0 -37
- package/src/test/ollama.ts +0 -86
- package/src/test/provider/index.ts +0 -7
- package/src/test/siliconflow/common.ts +0 -15
- package/src/test/siliconflow/get.ts +0 -22
- package/src/test/siliconflow/knowledge/create.ts +0 -18
- package/src/test/siliconflow/knowledge/qwen.md +0 -232
- package/src/test/siliconflow/rerank/fc.ts +0 -28
- package/src/test/siliconflow/rerank/index.ts +0 -34
- package/src/test/siliconflow/videos/index.ts +0 -100
- package/src/utils/json.ts +0 -12
package/dist/ai-provider.d.ts
CHANGED
|
@@ -1,25 +1,171 @@
|
|
|
1
|
-
import * as openai_resources_index_mjs from 'openai/resources/index.mjs';
|
|
2
|
-
import OpenAI, { OpenAI as OpenAI$1 } from 'openai';
|
|
3
|
-
import * as openai_resources_embeddings_mjs from 'openai/resources/embeddings.mjs';
|
|
4
1
|
import * as _kevisual_permission from '@kevisual/permission';
|
|
5
2
|
import { Permission } from '@kevisual/permission';
|
|
6
3
|
|
|
7
|
-
type ChatMessage =
|
|
8
|
-
|
|
4
|
+
type ChatMessage = {
|
|
5
|
+
role?: 'user' | 'assistant' | 'system' | 'tool';
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
type ChatMessageOptions<T = {}> = {
|
|
9
|
+
messages?: ChatMessage[];
|
|
10
|
+
/**
|
|
11
|
+
* 模型名称
|
|
12
|
+
*/
|
|
13
|
+
model?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 温度参数,控制随机性 (0-2)
|
|
16
|
+
* 较高的值如0.8会使输出更随机,较低的值如0.2会使其更集中和确定
|
|
17
|
+
*/
|
|
18
|
+
temperature?: number;
|
|
19
|
+
/**
|
|
20
|
+
* 核采样参数 (0-1)
|
|
21
|
+
* 与temperature类似,但使用不同的采样方法
|
|
22
|
+
*/
|
|
23
|
+
top_p?: number;
|
|
24
|
+
/**
|
|
25
|
+
* 生成的最大令牌数
|
|
26
|
+
*/
|
|
27
|
+
max_tokens?: number;
|
|
28
|
+
/**
|
|
29
|
+
* 停止序列
|
|
30
|
+
* 当遇到这些序列时停止生成
|
|
31
|
+
*/
|
|
32
|
+
stop?: string | string[];
|
|
33
|
+
/**
|
|
34
|
+
* 频率惩罚 (-2.0 到 2.0)
|
|
35
|
+
* 正值会根据新令牌在文本中的现有频率来惩罚它们
|
|
36
|
+
*/
|
|
37
|
+
frequency_penalty?: number;
|
|
38
|
+
/**
|
|
39
|
+
* 存在惩罚 (-2.0 到 2.0)
|
|
40
|
+
* 正值会根据新令牌是否出现在文本中来惩罚它们
|
|
41
|
+
*/
|
|
42
|
+
presence_penalty?: number;
|
|
43
|
+
/**
|
|
44
|
+
* 流式输出
|
|
45
|
+
*/
|
|
46
|
+
stream?: boolean;
|
|
9
47
|
/**
|
|
10
48
|
* 是否能够思考
|
|
11
|
-
* 如果会话是千文,服务器的接口,默认为
|
|
49
|
+
* 如果会话是千文,服务器的接口,默认为 false
|
|
12
50
|
*/
|
|
13
51
|
enable_thinking?: boolean;
|
|
52
|
+
response_format?: 'text' | 'json' | 'xml' | 'html';
|
|
53
|
+
/**
|
|
54
|
+
* 工具调用参数
|
|
55
|
+
*/
|
|
56
|
+
tool_calls?: any;
|
|
57
|
+
[key: string]: any;
|
|
58
|
+
} & T;
|
|
59
|
+
type Choice = {
|
|
60
|
+
finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call';
|
|
61
|
+
index: number;
|
|
62
|
+
message: {
|
|
63
|
+
role: 'assistant' | 'tool';
|
|
64
|
+
content: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
type ChatMessageComplete = {
|
|
68
|
+
/**
|
|
69
|
+
* 聊天完成的唯一标识符
|
|
70
|
+
*/
|
|
71
|
+
id: string;
|
|
72
|
+
/**
|
|
73
|
+
* 聊天完成选项列表
|
|
74
|
+
* 如果 n 大于 1,可以有多个选项
|
|
75
|
+
*/
|
|
76
|
+
choices: Array<Choice>;
|
|
77
|
+
/**
|
|
78
|
+
* 聊天完成创建时的 Unix 时间戳(秒)
|
|
79
|
+
*/
|
|
80
|
+
created: number;
|
|
81
|
+
/**
|
|
82
|
+
* 用于聊天完成的模型名称
|
|
83
|
+
*/
|
|
84
|
+
model: string;
|
|
85
|
+
/**
|
|
86
|
+
* 对象类型,始终为 `chat.completion`
|
|
87
|
+
*/
|
|
88
|
+
object: 'chat.completion';
|
|
89
|
+
/**
|
|
90
|
+
* 系统指纹
|
|
91
|
+
* 用于标识后端配置
|
|
92
|
+
*/
|
|
93
|
+
system_fingerprint?: string;
|
|
94
|
+
/**
|
|
95
|
+
* 完成请求的使用统计信息
|
|
96
|
+
*/
|
|
97
|
+
usage?: Usage;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* 向量嵌入请求参数
|
|
101
|
+
*/
|
|
102
|
+
type EmbeddingMessage = {
|
|
103
|
+
/**
|
|
104
|
+
* 输入文本或文本数组
|
|
105
|
+
* 要生成嵌入向量的文本内容
|
|
106
|
+
*/
|
|
107
|
+
input: string | string[];
|
|
108
|
+
/**
|
|
109
|
+
* 模型名称
|
|
110
|
+
* 用于生成嵌入向量的模型
|
|
111
|
+
*/
|
|
112
|
+
model: string;
|
|
113
|
+
/**
|
|
114
|
+
* 编码格式
|
|
115
|
+
* 返回的嵌入向量编码格式
|
|
116
|
+
*/
|
|
117
|
+
encoding_format?: 'float' | 'base64';
|
|
118
|
+
/**
|
|
119
|
+
* 维度
|
|
120
|
+
* 输出嵌入向量的维度(某些模型支持)
|
|
121
|
+
*/
|
|
122
|
+
dimensions?: number;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* 单个嵌入向量对象
|
|
126
|
+
*/
|
|
127
|
+
type EmbeddingObject = {
|
|
128
|
+
/**
|
|
129
|
+
* 对象类型,始终为 `embedding`
|
|
130
|
+
*/
|
|
131
|
+
object: 'embedding';
|
|
132
|
+
/**
|
|
133
|
+
* 嵌入向量
|
|
134
|
+
* 浮点数数组,表示文本的向量表示
|
|
135
|
+
*/
|
|
136
|
+
embedding: number[];
|
|
137
|
+
/**
|
|
138
|
+
* 索引位置
|
|
139
|
+
* 该嵌入在输入数组中的位置
|
|
140
|
+
*/
|
|
141
|
+
index: number;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* 向量嵌入响应结果
|
|
145
|
+
*/
|
|
146
|
+
type EmbeddingMessageComplete = {
|
|
147
|
+
/**
|
|
148
|
+
* 对象类型,始终为 `list`
|
|
149
|
+
*/
|
|
150
|
+
object: 'list';
|
|
151
|
+
/**
|
|
152
|
+
* 嵌入向量数据列表
|
|
153
|
+
*/
|
|
154
|
+
data: EmbeddingObject[];
|
|
155
|
+
/**
|
|
156
|
+
* 使用的模型名称
|
|
157
|
+
*/
|
|
158
|
+
model: string;
|
|
159
|
+
/**
|
|
160
|
+
* 使用统计信息
|
|
161
|
+
*/
|
|
162
|
+
usage: Usage;
|
|
14
163
|
};
|
|
15
|
-
type ChatMessageComplete = OpenAI.Chat.Completions.ChatCompletion;
|
|
16
|
-
type ChatMessageStream = OpenAI.Chat.Completions.ChatCompletion;
|
|
17
|
-
type EmbeddingMessage = Partial<OpenAI.Embeddings.EmbeddingCreateParams>;
|
|
18
|
-
type EmbeddingMessageComplete = OpenAI.Embeddings.CreateEmbeddingResponse;
|
|
19
164
|
interface BaseChatInterface {
|
|
165
|
+
chat(options: ChatMessageOptions): Promise<ChatMessageComplete>;
|
|
20
166
|
chat(messages: ChatMessage[], options?: ChatMessageOptions): Promise<ChatMessageComplete>;
|
|
21
167
|
}
|
|
22
|
-
interface
|
|
168
|
+
interface Usage {
|
|
23
169
|
/**
|
|
24
170
|
* 提示词令牌
|
|
25
171
|
*/
|
|
@@ -132,7 +278,7 @@ type BaseChatOptions<T = Record<string, any>> = {
|
|
|
132
278
|
*/
|
|
133
279
|
stream?: boolean;
|
|
134
280
|
} & T;
|
|
135
|
-
declare class BaseChat implements BaseChatInterface,
|
|
281
|
+
declare class BaseChat implements BaseChatInterface, Usage {
|
|
136
282
|
/**
|
|
137
283
|
* 默认baseURL
|
|
138
284
|
*/
|
|
@@ -161,8 +307,17 @@ declare class BaseChat implements BaseChatInterface, BaseChatUsageInterface {
|
|
|
161
307
|
/**
|
|
162
308
|
* 聊天
|
|
163
309
|
*/
|
|
310
|
+
chat(options: ChatMessageOptions): Promise<ChatMessageComplete>;
|
|
164
311
|
chat(messages: ChatMessage[], options?: ChatMessageOptions): Promise<ChatMessageComplete>;
|
|
165
|
-
chatStream(
|
|
312
|
+
chatStream(options: ChatMessageOptions): AsyncGenerator<ChatMessageComplete>;
|
|
313
|
+
chatStream(messages: ChatMessage[], options?: ChatMessageOptions): AsyncGenerator<ChatMessageComplete>;
|
|
314
|
+
/**
|
|
315
|
+
* 简单提问接口
|
|
316
|
+
* @param message
|
|
317
|
+
* @param options
|
|
318
|
+
* @returns
|
|
319
|
+
*/
|
|
320
|
+
question(message: string, options?: ChatMessageOptions): Promise<ChatMessageComplete>;
|
|
166
321
|
/**
|
|
167
322
|
* 获取聊天使用情况
|
|
168
323
|
* @returns
|
|
@@ -172,6 +327,11 @@ declare class BaseChat implements BaseChatInterface, BaseChatUsageInterface {
|
|
|
172
327
|
total_tokens: number;
|
|
173
328
|
completion_tokens: number;
|
|
174
329
|
};
|
|
330
|
+
setChatUsage(usage: {
|
|
331
|
+
prompt_tokens?: number;
|
|
332
|
+
total_tokens?: number;
|
|
333
|
+
completion_tokens?: number;
|
|
334
|
+
}): void;
|
|
175
335
|
getHeaders(headers?: Record<string, string>): {
|
|
176
336
|
'Content-Type': string;
|
|
177
337
|
Authorization: string;
|
|
@@ -211,7 +371,6 @@ type OllamaModel = {
|
|
|
211
371
|
declare class Ollama extends BaseChat {
|
|
212
372
|
static BASE_URL: string;
|
|
213
373
|
constructor(options: OllamaOptions$1);
|
|
214
|
-
chat(messages: ChatMessage[], options?: ChatMessageOptions): Promise<openai_resources_index_mjs.ChatCompletion>;
|
|
215
374
|
/**
|
|
216
375
|
* 获取模型列表
|
|
217
376
|
* @returns
|
|
@@ -249,7 +408,6 @@ declare class SiliconFlow extends BaseChat {
|
|
|
249
408
|
static BASE_URL: string;
|
|
250
409
|
constructor(options: SiliconFlowOptions);
|
|
251
410
|
getUsageInfo(): Promise<SiliconFlowUsageResponse>;
|
|
252
|
-
chat(messages: OpenAI$1.Chat.Completions.ChatCompletionMessageParam[], options?: ChatMessageOptions): Promise<OpenAI$1.Chat.Completions.ChatCompletion>;
|
|
253
411
|
}
|
|
254
412
|
|
|
255
413
|
type OllamaOptions = BaseChatOptions;
|
|
@@ -348,7 +506,7 @@ declare class ProviderManager {
|
|
|
348
506
|
provider: BaseChat;
|
|
349
507
|
constructor(config: ProviderManagerConfig);
|
|
350
508
|
static createProvider(config: ProviderManagerConfig): Promise<BaseChat>;
|
|
351
|
-
chat(messages: ChatMessage[]): Promise<
|
|
509
|
+
chat(messages: ChatMessage[]): Promise<ChatMessageComplete>;
|
|
352
510
|
}
|
|
353
511
|
|
|
354
512
|
type KnowledgeOptions<T = Record<string, any>> = BaseChatOptions<{
|
|
@@ -376,7 +534,7 @@ declare class KnowledgeBase extends BaseChat {
|
|
|
376
534
|
*/
|
|
377
535
|
generateEmbedding(text: string | string[]): Promise<{
|
|
378
536
|
code: number;
|
|
379
|
-
data:
|
|
537
|
+
data: EmbeddingObject[];
|
|
380
538
|
message?: undefined;
|
|
381
539
|
} | {
|
|
382
540
|
code: any;
|
|
@@ -552,4 +710,4 @@ declare class AIConfigParser {
|
|
|
552
710
|
}
|
|
553
711
|
|
|
554
712
|
export { AIConfigParser, AIUtils, BailianChat, BailianProvider, BaseChat, ChatProviderMap, Custom, CustomProvider, DeepSeek, DeepSeekProvider, Kevisual, KevisualProvider, Kimi, KimiProvider, KnowledgeBase, ModelScope, ModelScopeProvider, Ollama, OllamaProvider, ProviderManager, SiliconFlow, SiliconFlowKnowledge, SiliconFlowProvider, Volces, VolcesProvider, Zhipu, ZhipuProvider, decryptAES, encryptAES, readStream };
|
|
555
|
-
export type { AIConfig, AIModel, BaseChatInterface, BaseChatOptions,
|
|
713
|
+
export type { AIConfig, AIModel, BaseChatInterface, BaseChatOptions, ChatMessage, ChatMessageComplete, ChatMessageOptions, ChatStream, EmbeddingMessage, EmbeddingMessageComplete, EmbeddingObject, GetProviderOpts, KnowledgeOptions, ProviderResult, RerankOptions, SecretKey, Usage };
|
package/dist/ai-provider.js
CHANGED
|
@@ -1350,10 +1350,10 @@ class BaseChat {
|
|
|
1350
1350
|
baseURL;
|
|
1351
1351
|
model;
|
|
1352
1352
|
apiKey;
|
|
1353
|
-
prompt_tokens;
|
|
1354
|
-
total_tokens;
|
|
1355
|
-
completion_tokens;
|
|
1356
|
-
responseText;
|
|
1353
|
+
prompt_tokens = 0;
|
|
1354
|
+
total_tokens = 0;
|
|
1355
|
+
completion_tokens = 0;
|
|
1356
|
+
responseText = "";
|
|
1357
1357
|
utils = AIUtils;
|
|
1358
1358
|
constructor(options) {
|
|
1359
1359
|
this.baseURL = options.baseURL;
|
|
@@ -1385,11 +1385,14 @@ class BaseChat {
|
|
|
1385
1385
|
}
|
|
1386
1386
|
}).then((res) => res.json());
|
|
1387
1387
|
}
|
|
1388
|
-
async chat(
|
|
1388
|
+
async chat(messagesOrOptions, options) {
|
|
1389
|
+
const isFirstParamOptions = !Array.isArray(messagesOrOptions);
|
|
1390
|
+
const messages = isFirstParamOptions ? messagesOrOptions.messages : messagesOrOptions;
|
|
1391
|
+
const opts = isFirstParamOptions ? messagesOrOptions : options || {};
|
|
1389
1392
|
const requestBody = {
|
|
1390
1393
|
model: this.model,
|
|
1391
1394
|
messages,
|
|
1392
|
-
...
|
|
1395
|
+
...opts,
|
|
1393
1396
|
stream: false
|
|
1394
1397
|
};
|
|
1395
1398
|
const response = await this.post(`${this.baseURL}/chat/completions`, { data: requestBody });
|
|
@@ -1398,20 +1401,21 @@ class BaseChat {
|
|
|
1398
1401
|
throw new Error(`Chat API request failed: ${response.status} ${response.statusText} - ${errorText}`);
|
|
1399
1402
|
}
|
|
1400
1403
|
const res = await response.json();
|
|
1401
|
-
this.
|
|
1402
|
-
this.total_tokens = res.usage?.total_tokens ?? 0;
|
|
1403
|
-
this.completion_tokens = res.usage?.completion_tokens ?? 0;
|
|
1404
|
+
this.setChatUsage(res.usage);
|
|
1404
1405
|
this.responseText = res.choices[0]?.message?.content || "";
|
|
1405
1406
|
return res;
|
|
1406
1407
|
}
|
|
1407
|
-
async chatStream(
|
|
1408
|
-
|
|
1408
|
+
async* chatStream(messagesOrOptions, options) {
|
|
1409
|
+
const isFirstParamOptions = !Array.isArray(messagesOrOptions);
|
|
1410
|
+
const messages = isFirstParamOptions ? messagesOrOptions.messages : messagesOrOptions;
|
|
1411
|
+
const opts = isFirstParamOptions ? messagesOrOptions : options || {};
|
|
1412
|
+
if (opts.response_format) {
|
|
1409
1413
|
throw new Error("response_format is not supported in stream mode");
|
|
1410
1414
|
}
|
|
1411
1415
|
const requestBody = {
|
|
1412
1416
|
model: this.model,
|
|
1413
1417
|
messages,
|
|
1414
|
-
...
|
|
1418
|
+
...opts,
|
|
1415
1419
|
stream: true
|
|
1416
1420
|
};
|
|
1417
1421
|
const response = await this.post(`${this.baseURL}/chat/completions`, { data: requestBody });
|
|
@@ -1452,6 +1456,12 @@ class BaseChat {
|
|
|
1452
1456
|
});
|
|
1453
1457
|
return stream;
|
|
1454
1458
|
}
|
|
1459
|
+
question(message, options) {
|
|
1460
|
+
const messages = [
|
|
1461
|
+
{ role: "user", content: message }
|
|
1462
|
+
];
|
|
1463
|
+
return this.chat(messages, options);
|
|
1464
|
+
}
|
|
1455
1465
|
getChatUsage() {
|
|
1456
1466
|
return {
|
|
1457
1467
|
prompt_tokens: this.prompt_tokens,
|
|
@@ -1459,6 +1469,11 @@ class BaseChat {
|
|
|
1459
1469
|
completion_tokens: this.completion_tokens
|
|
1460
1470
|
};
|
|
1461
1471
|
}
|
|
1472
|
+
setChatUsage(usage) {
|
|
1473
|
+
this.prompt_tokens = usage.prompt_tokens ?? this.prompt_tokens;
|
|
1474
|
+
this.total_tokens = usage.total_tokens ?? this.total_tokens;
|
|
1475
|
+
this.completion_tokens = usage.completion_tokens ?? this.completion_tokens;
|
|
1476
|
+
}
|
|
1462
1477
|
getHeaders(headers) {
|
|
1463
1478
|
return {
|
|
1464
1479
|
"Content-Type": "application/json",
|
|
@@ -1499,11 +1514,6 @@ class Ollama extends BaseChat {
|
|
|
1499
1514
|
const baseURL = options.baseURL || Ollama.BASE_URL;
|
|
1500
1515
|
super({ ...options, baseURL });
|
|
1501
1516
|
}
|
|
1502
|
-
async chat(messages, options) {
|
|
1503
|
-
const res = await super.chat(messages, options);
|
|
1504
|
-
console.log("thunk", this.getChatUsage());
|
|
1505
|
-
return res;
|
|
1506
|
-
}
|
|
1507
1517
|
async listModels() {
|
|
1508
1518
|
const _url = new URL(this.baseURL);
|
|
1509
1519
|
const tagsURL = new URL("/api/tags", _url);
|
|
@@ -1526,10 +1536,6 @@ class SiliconFlow extends BaseChat {
|
|
|
1526
1536
|
async getUsageInfo() {
|
|
1527
1537
|
return this.get("/user/info");
|
|
1528
1538
|
}
|
|
1529
|
-
async chat(messages, options) {
|
|
1530
|
-
const res = await super.chat(messages, options);
|
|
1531
|
-
return res;
|
|
1532
|
-
}
|
|
1533
1539
|
}
|
|
1534
1540
|
|
|
1535
1541
|
// src/provider/chat-adapter/custom.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/ai",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "AI Center Services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"basename": "/root/ai-center-services",
|
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
"src",
|
|
14
14
|
"types"
|
|
15
15
|
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "npm run clean && bun bun.config.mjs",
|
|
18
|
+
"dev": "bun run --watch bun.config.mjs",
|
|
19
|
+
"test": "tsx test/**/*.ts",
|
|
20
|
+
"clean": "rm -rf dist",
|
|
21
|
+
"pub": "envision pack -p -u"
|
|
22
|
+
},
|
|
16
23
|
"keywords": [
|
|
17
24
|
"kevisual",
|
|
18
25
|
"ai",
|
|
@@ -20,6 +27,7 @@
|
|
|
20
27
|
],
|
|
21
28
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
|
22
29
|
"license": "MIT",
|
|
30
|
+
"packageManager": "pnpm@10.28.0",
|
|
23
31
|
"type": "module",
|
|
24
32
|
"publishConfig": {
|
|
25
33
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -45,34 +53,27 @@
|
|
|
45
53
|
}
|
|
46
54
|
},
|
|
47
55
|
"devDependencies": {
|
|
48
|
-
"@kevisual/router": "0.0.
|
|
56
|
+
"@kevisual/router": "0.0.52",
|
|
49
57
|
"@kevisual/types": "^0.0.10",
|
|
50
58
|
"@kevisual/use-config": "^1.0.21",
|
|
51
|
-
"@types/bun": "^1.3.
|
|
59
|
+
"@types/bun": "^1.3.5",
|
|
52
60
|
"@types/crypto-js": "^4.2.2",
|
|
53
61
|
"@types/formidable": "^3.4.6",
|
|
54
|
-
"@types/node": "^
|
|
62
|
+
"@types/node": "^25.0.5",
|
|
55
63
|
"cross-env": "^10.1.0",
|
|
56
64
|
"crypto-js": "^4.2.0",
|
|
57
65
|
"dayjs": "^1.11.19",
|
|
58
66
|
"dotenv": "^17.2.3",
|
|
59
67
|
"formidable": "^3.5.4",
|
|
60
|
-
"openai": "6.
|
|
68
|
+
"openai": "6.16.0",
|
|
61
69
|
"pm2": "^6.0.14",
|
|
62
70
|
"rimraf": "^6.1.2",
|
|
63
71
|
"typescript": "^5.9.3",
|
|
64
|
-
"vite": "^7.
|
|
72
|
+
"vite": "^7.3.1"
|
|
65
73
|
},
|
|
66
74
|
"dependencies": {
|
|
67
75
|
"@kevisual/logger": "^0.0.4",
|
|
68
76
|
"@kevisual/permission": "^0.0.3",
|
|
69
|
-
"@kevisual/query": "^0.0.
|
|
70
|
-
},
|
|
71
|
-
"scripts": {
|
|
72
|
-
"build": "npm run clean && bun bun.config.mjs",
|
|
73
|
-
"dev": "bun run --watch bun.config.mjs",
|
|
74
|
-
"test": "tsx test/**/*.ts",
|
|
75
|
-
"clean": "rm -rf dist",
|
|
76
|
-
"pub": "envision pack -p -u"
|
|
77
|
+
"@kevisual/query": "^0.0.35"
|
|
77
78
|
}
|
|
78
79
|
}
|
package/src/jimeng/core.ts
CHANGED
|
@@ -1,51 +1,121 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { Result } from '@kevisual/query'
|
|
2
|
+
export interface JimengOptions {
|
|
3
|
+
/** API密钥,用于认证请求 */
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** API基础URL */
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
/** 请求超时时间(毫秒) */
|
|
8
|
+
timeout: number;
|
|
5
9
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
|
|
11
|
+
export interface JimengGenerateOptions {
|
|
12
|
+
/** 图片生成提示词 */
|
|
13
|
+
prompt: string;
|
|
14
|
+
/** 使用的模型版本,默认 jimeng-4.0 */
|
|
15
|
+
model?: string;
|
|
16
|
+
/** 图片比例,默认 1:1 */
|
|
17
|
+
ratio?: string;
|
|
18
|
+
/** 图片分辨率,默认 2k */
|
|
19
|
+
resolution?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface JimengResponse {
|
|
23
|
+
/** 请求创建时间戳 */
|
|
24
|
+
created: number;
|
|
25
|
+
/** 生成的图片列表 */
|
|
26
|
+
data: Array<{
|
|
27
|
+
/** 图片URL */
|
|
28
|
+
url: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class JimengService {
|
|
33
|
+
private apiKey: string;
|
|
34
|
+
private baseUrl: string;
|
|
35
|
+
private timeout: number;
|
|
36
|
+
|
|
37
|
+
constructor(options: JimengOptions) {
|
|
38
|
+
this.apiKey = options.apiKey;
|
|
39
|
+
this.baseUrl = options.baseUrl || 'https://jimeng-api.kevisual.cn/v1';
|
|
40
|
+
this.timeout = options.timeout;
|
|
17
41
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
42
|
+
|
|
43
|
+
async generateImage(options: JimengGenerateOptions): Promise<Result<JimengResponse>> {
|
|
44
|
+
const {
|
|
45
|
+
prompt,
|
|
46
|
+
model = 'jimeng-4.6',
|
|
47
|
+
ratio = '1:1',
|
|
48
|
+
resolution = '2k'
|
|
49
|
+
} = options;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
54
|
+
|
|
55
|
+
const response = await fetch(`${this.baseUrl}/images/generations`, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
model,
|
|
63
|
+
prompt,
|
|
64
|
+
ratio,
|
|
65
|
+
resolution,
|
|
66
|
+
}),
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
clearTimeout(timeoutId);
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`jimeng API error: ${response.status} ${response.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const result = await response.json() as JimengResponse;
|
|
77
|
+
return { code: 200, data: result };
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
return { code: 500, message: error.message || 'Unknown error' };
|
|
22
80
|
}
|
|
23
81
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
82
|
+
|
|
83
|
+
async downloadImage(url: string): Promise<Uint8Array> {
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const response = await fetch(url, {
|
|
89
|
+
signal: controller.signal,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
clearTimeout(timeoutId);
|
|
93
|
+
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(`Failed to download image: ${response.statusText}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
99
|
+
return new Uint8Array(arrayBuffer);
|
|
100
|
+
} catch (error: any) {
|
|
101
|
+
clearTimeout(timeoutId);
|
|
102
|
+
if (error.name === 'AbortError') {
|
|
103
|
+
throw new Error('Image download timeout');
|
|
33
104
|
}
|
|
34
|
-
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** 获取图片过期时间 */
|
|
109
|
+
async getExpiredTime(url: string): Promise<{ expiredAt: number, expired: boolean }> {
|
|
110
|
+
// https://p3-dreamina-sign.byteimg.com/tos-cn-i-tb4s082cfz/c018e06ee6654dd78ccacb29eff4744e~tplv-tb4s082cfz-aigc_resize:0:0.png?lk3s=43402efa&x-expires=1767852000&x-signature=34yf37N955BP37eLaYEzKeLQn0Q%3D&format=.png
|
|
111
|
+
const urlObj = new URL(url);
|
|
112
|
+
let expires = urlObj.searchParams.get('x-expires');
|
|
113
|
+
if (!expires) {
|
|
114
|
+
expires = '0';
|
|
115
|
+
}
|
|
116
|
+
const expiredAt = parseInt(expires) * 1000;
|
|
117
|
+
const expired = Date.now() > expiredAt;
|
|
118
|
+
return { expiredAt, expired };
|
|
35
119
|
}
|
|
36
120
|
}
|
|
37
121
|
|
|
38
|
-
export type ImageOptions = {
|
|
39
|
-
model?: string;
|
|
40
|
-
prompt: string;
|
|
41
|
-
/**
|
|
42
|
-
* 宽高比,如 "16:9", "4:3", "1:1" 等
|
|
43
|
-
*/
|
|
44
|
-
ratio?: string;
|
|
45
|
-
/**
|
|
46
|
-
*
|
|
47
|
-
* 图片分辨率,如 "1024x768", "512x512" 等
|
|
48
|
-
* 4k 2k
|
|
49
|
-
*/
|
|
50
|
-
resolution?: string;
|
|
51
|
-
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseChat, type BaseChatOptions } from "../chat.ts";
|
|
2
|
+
|
|
3
|
+
type MimoOptions = Partial<BaseChatOptions>;
|
|
4
|
+
export class MimoChat extends BaseChat {
|
|
5
|
+
static BASE_URL = 'https://api.xiaomimimo.com/v1';
|
|
6
|
+
constructor(options: MimoOptions) {
|
|
7
|
+
const baseURL = options.baseURL || MimoChat.BASE_URL;
|
|
8
|
+
super({ ...(options as BaseChatOptions), baseURL: baseURL });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -25,11 +25,6 @@ export class Ollama extends BaseChat {
|
|
|
25
25
|
const baseURL = options.baseURL || Ollama.BASE_URL;
|
|
26
26
|
super({ ...(options as BaseChatOptions), baseURL: baseURL });
|
|
27
27
|
}
|
|
28
|
-
async chat(messages: ChatMessage[], options?: ChatMessageOptions) {
|
|
29
|
-
const res = await super.chat(messages, options);
|
|
30
|
-
console.log('thunk', this.getChatUsage());
|
|
31
|
-
return res;
|
|
32
|
-
}
|
|
33
28
|
/**
|
|
34
29
|
* 获取模型列表
|
|
35
30
|
* @returns
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BaseChat, BaseChatOptions } from '../core/chat.ts';
|
|
2
|
-
import { OpenAI } from 'openai';
|
|
3
2
|
import type { ChatMessage, ChatMessageOptions } from '../core/index.ts';
|
|
4
3
|
|
|
5
4
|
export type SiliconFlowOptions = Partial<BaseChatOptions>;
|
|
@@ -33,8 +32,4 @@ export class SiliconFlow extends BaseChat {
|
|
|
33
32
|
async getUsageInfo(): Promise<SiliconFlowUsageResponse> {
|
|
34
33
|
return this.get('/user/info');
|
|
35
34
|
}
|
|
36
|
-
async chat(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], options?: ChatMessageOptions) {
|
|
37
|
-
const res = await super.chat(messages, options);
|
|
38
|
-
return res;
|
|
39
|
-
}
|
|
40
35
|
}
|