koishi-plugin-chatluna-google-gemini-adapter 1.0.0-beta.2 → 1.0.0-beta.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/lib/index.cjs +653 -0
- package/lib/index.d.ts +111 -12
- package/lib/index.mjs +645 -0
- package/package.json +20 -8
- package/lib/client.d.ts +0 -17
- package/lib/client.js +0 -75
- package/lib/index.js +0 -63
- package/lib/requester.d.ts +0 -16
- package/lib/requester.js +0 -206
- package/lib/types.d.ts +0 -36
- package/lib/types.js +0 -2
- package/lib/utils.d.ts +0 -5
- package/lib/utils.js +0 -112
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name2 in all)
|
|
8
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
Config: () => Config,
|
|
24
|
+
apply: () => apply,
|
|
25
|
+
inject: () => inject,
|
|
26
|
+
logger: () => logger,
|
|
27
|
+
name: () => name
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(src_exports);
|
|
30
|
+
var import_chat = require("koishi-plugin-chatluna/services/chat");
|
|
31
|
+
var import_koishi = require("koishi");
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
var import_client = require("koishi-plugin-chatluna/llm-core/platform/client");
|
|
35
|
+
var import_model = require("koishi-plugin-chatluna/llm-core/platform/model");
|
|
36
|
+
var import_types = require("koishi-plugin-chatluna/llm-core/platform/types");
|
|
37
|
+
var import_error2 = require("koishi-plugin-chatluna/utils/error");
|
|
38
|
+
|
|
39
|
+
// src/requester.ts
|
|
40
|
+
var import_messages2 = require("@langchain/core/messages");
|
|
41
|
+
var import_outputs = require("@langchain/core/outputs");
|
|
42
|
+
var import_json = require("@streamparser/json");
|
|
43
|
+
var import_api = require("koishi-plugin-chatluna/llm-core/platform/api");
|
|
44
|
+
var import_error = require("koishi-plugin-chatluna/utils/error");
|
|
45
|
+
var import_sse = require("koishi-plugin-chatluna/utils/sse");
|
|
46
|
+
var import_stream = require("koishi-plugin-chatluna/utils/stream");
|
|
47
|
+
|
|
48
|
+
// src/utils.ts
|
|
49
|
+
var import_messages = require("@langchain/core/messages");
|
|
50
|
+
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
51
|
+
async function langchainMessageToGeminiMessage(messages, model) {
|
|
52
|
+
const mappedMessage = await Promise.all(
|
|
53
|
+
messages.map(async (rawMessage) => {
|
|
54
|
+
const role = messageTypeToGeminiRole(rawMessage._getType());
|
|
55
|
+
if (role === "function" || rawMessage.additional_kwargs?.function_call != null) {
|
|
56
|
+
return {
|
|
57
|
+
role: "function",
|
|
58
|
+
parts: [
|
|
59
|
+
{
|
|
60
|
+
functionResponse: rawMessage.additional_kwargs?.function_call != null ? void 0 : {
|
|
61
|
+
name: rawMessage.name,
|
|
62
|
+
response: {
|
|
63
|
+
name: rawMessage.name,
|
|
64
|
+
content: (() => {
|
|
65
|
+
try {
|
|
66
|
+
const result3 = JSON.parse(
|
|
67
|
+
rawMessage.content
|
|
68
|
+
);
|
|
69
|
+
if (typeof result3 === "string") {
|
|
70
|
+
return {
|
|
71
|
+
response: result3
|
|
72
|
+
};
|
|
73
|
+
} else {
|
|
74
|
+
return result3;
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return {
|
|
78
|
+
response: rawMessage.content
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
})()
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
functionCall: rawMessage.additional_kwargs?.function_call != null ? {
|
|
85
|
+
name: rawMessage.additional_kwargs.function_call.name,
|
|
86
|
+
args: (() => {
|
|
87
|
+
try {
|
|
88
|
+
const result3 = JSON.parse(
|
|
89
|
+
rawMessage.additional_kwargs.function_call.arguments
|
|
90
|
+
);
|
|
91
|
+
if (typeof result3 === "string") {
|
|
92
|
+
return {
|
|
93
|
+
input: result3
|
|
94
|
+
};
|
|
95
|
+
} else {
|
|
96
|
+
return result3;
|
|
97
|
+
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
return {
|
|
100
|
+
input: rawMessage.additional_kwargs.function_call.arguments
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
})()
|
|
104
|
+
} : void 0
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const images = rawMessage.additional_kwargs.images;
|
|
110
|
+
const result2 = {
|
|
111
|
+
role,
|
|
112
|
+
parts: [
|
|
113
|
+
{
|
|
114
|
+
text: rawMessage.content
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
if ((model.includes("vision") || model.includes("gemini-1.5")) && images != null) {
|
|
119
|
+
for (const image of images) {
|
|
120
|
+
result2.parts.push({
|
|
121
|
+
inline_data: {
|
|
122
|
+
// base64 image match type
|
|
123
|
+
data: image.replace(/^data:image\/\w+;base64,/, ""),
|
|
124
|
+
mime_type: "image/jpeg"
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result2;
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
const result = [];
|
|
133
|
+
for (let i = 0; i < mappedMessage.length; i++) {
|
|
134
|
+
const message = mappedMessage[i];
|
|
135
|
+
if (message.role !== "system") {
|
|
136
|
+
result.push(message);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
result.push({
|
|
140
|
+
role: "user",
|
|
141
|
+
parts: message.parts
|
|
142
|
+
});
|
|
143
|
+
if (mappedMessage?.[i + 1]?.role === "model") {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (mappedMessage?.[i + 1]?.role === "user") {
|
|
147
|
+
result.push({
|
|
148
|
+
role: "model",
|
|
149
|
+
parts: [{ text: "Okay, what do I need to do?" }]
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (result[result.length - 1].role === "model") {
|
|
154
|
+
result.push({
|
|
155
|
+
role: "user",
|
|
156
|
+
parts: [
|
|
157
|
+
{
|
|
158
|
+
text: "Continue what I said to you last message. Follow these instructions."
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (model.includes("vision")) {
|
|
164
|
+
const textBuffer = [];
|
|
165
|
+
const last = result.pop();
|
|
166
|
+
for (let i = 0; i < result.length; i++) {
|
|
167
|
+
const message = result[i];
|
|
168
|
+
const text = message.parts[0].text;
|
|
169
|
+
textBuffer.push(`${message.role}: ${text}`);
|
|
170
|
+
}
|
|
171
|
+
const lastParts = last.parts;
|
|
172
|
+
let lastImagesParts = lastParts.filter(
|
|
173
|
+
(part) => part.inline_data?.mime_type === "image/jpeg"
|
|
174
|
+
);
|
|
175
|
+
if (lastImagesParts.length < 1) {
|
|
176
|
+
for (let i = result.length - 1; i >= 0; i--) {
|
|
177
|
+
const message = result[i];
|
|
178
|
+
const images = message.parts.filter(
|
|
179
|
+
(part) => part.inline_data?.mime_type === "image/jpeg"
|
|
180
|
+
);
|
|
181
|
+
if (images.length > 0) {
|
|
182
|
+
lastImagesParts = images;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
;
|
|
188
|
+
lastParts.filter(
|
|
189
|
+
(part) => part.text !== void 0 && part.text !== null
|
|
190
|
+
).forEach((part) => {
|
|
191
|
+
textBuffer.push(`${last.role}: ${part.text}`);
|
|
192
|
+
});
|
|
193
|
+
return [
|
|
194
|
+
{
|
|
195
|
+
role: "user",
|
|
196
|
+
parts: [
|
|
197
|
+
{
|
|
198
|
+
text: textBuffer.join("\n")
|
|
199
|
+
},
|
|
200
|
+
...lastImagesParts
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
];
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
__name(langchainMessageToGeminiMessage, "langchainMessageToGeminiMessage");
|
|
208
|
+
function partAsType(part) {
|
|
209
|
+
return part;
|
|
210
|
+
}
|
|
211
|
+
__name(partAsType, "partAsType");
|
|
212
|
+
function formatToolsToGeminiAITools(tools) {
|
|
213
|
+
if (tools.length < 1) {
|
|
214
|
+
return void 0;
|
|
215
|
+
}
|
|
216
|
+
return tools.map(formatToolToGeminiAITool);
|
|
217
|
+
}
|
|
218
|
+
__name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
|
|
219
|
+
function formatToolToGeminiAITool(tool) {
|
|
220
|
+
const parameters = (0, import_zod_to_json_schema.zodToJsonSchema)(tool.schema);
|
|
221
|
+
delete parameters["$schema"];
|
|
222
|
+
delete parameters["additionalProperties"];
|
|
223
|
+
return {
|
|
224
|
+
name: tool.name,
|
|
225
|
+
description: tool.description,
|
|
226
|
+
// any?
|
|
227
|
+
parameters
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
__name(formatToolToGeminiAITool, "formatToolToGeminiAITool");
|
|
231
|
+
function messageTypeToGeminiRole(type) {
|
|
232
|
+
switch (type) {
|
|
233
|
+
case "system":
|
|
234
|
+
return "system";
|
|
235
|
+
case "ai":
|
|
236
|
+
return "model";
|
|
237
|
+
case "human":
|
|
238
|
+
return "user";
|
|
239
|
+
case "function":
|
|
240
|
+
return "function";
|
|
241
|
+
default:
|
|
242
|
+
throw new Error(`Unknown message type: ${type}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
__name(messageTypeToGeminiRole, "messageTypeToGeminiRole");
|
|
246
|
+
|
|
247
|
+
// src/requester.ts
|
|
248
|
+
var GeminiRequester = class extends import_api.ModelRequester {
|
|
249
|
+
constructor(_config, _plugin) {
|
|
250
|
+
super();
|
|
251
|
+
this._config = _config;
|
|
252
|
+
this._plugin = _plugin;
|
|
253
|
+
}
|
|
254
|
+
static {
|
|
255
|
+
__name(this, "GeminiRequester");
|
|
256
|
+
}
|
|
257
|
+
async *completionStream(params) {
|
|
258
|
+
try {
|
|
259
|
+
const response = await this._post(
|
|
260
|
+
`models/${params.model}:streamGenerateContent`,
|
|
261
|
+
{
|
|
262
|
+
contents: await langchainMessageToGeminiMessage(
|
|
263
|
+
params.input,
|
|
264
|
+
params.model
|
|
265
|
+
),
|
|
266
|
+
safetySettings: [
|
|
267
|
+
{
|
|
268
|
+
category: "HARM_CATEGORY_HARASSMENT",
|
|
269
|
+
threshold: "BLOCK_NONE"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
category: "HARM_CATEGORY_HATE_SPEECH",
|
|
273
|
+
threshold: "BLOCK_NONE"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
|
|
277
|
+
threshold: "BLOCK_NONE"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
category: "HARM_CATEGORY_DANGEROUS_CONTENT",
|
|
281
|
+
threshold: "BLOCK_NONE"
|
|
282
|
+
}
|
|
283
|
+
],
|
|
284
|
+
generationConfig: {
|
|
285
|
+
stopSequences: params.stop,
|
|
286
|
+
temperature: params.temperature,
|
|
287
|
+
maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
|
|
288
|
+
topP: params.topP
|
|
289
|
+
},
|
|
290
|
+
tools: !params.model.includes("vision") && params.tools != null ? {
|
|
291
|
+
functionDeclarations: formatToolsToGeminiAITools(params.tools)
|
|
292
|
+
} : void 0
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
signal: params.signal
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
let errorCount = 0;
|
|
299
|
+
const stream = new TransformStream();
|
|
300
|
+
const iterable = (0, import_stream.readableStreamToAsyncIterable)(
|
|
301
|
+
stream.readable
|
|
302
|
+
);
|
|
303
|
+
const jsonParser = new import_json.JSONParser();
|
|
304
|
+
const writable = stream.writable.getWriter();
|
|
305
|
+
jsonParser.onEnd = async () => {
|
|
306
|
+
await writable.close();
|
|
307
|
+
};
|
|
308
|
+
jsonParser.onValue = async ({ value }) => {
|
|
309
|
+
const transformValue = value;
|
|
310
|
+
if (transformValue.candidates && transformValue.candidates[0]) {
|
|
311
|
+
const parts = transformValue.candidates[0]?.content?.parts;
|
|
312
|
+
if (parts == null || parts.length < 1) {
|
|
313
|
+
throw new Error(JSON.stringify(value));
|
|
314
|
+
}
|
|
315
|
+
for (const part of parts) {
|
|
316
|
+
await writable.write(part);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
await (0, import_sse.sse)(
|
|
321
|
+
response,
|
|
322
|
+
async (rawData) => {
|
|
323
|
+
jsonParser.write(rawData);
|
|
324
|
+
return true;
|
|
325
|
+
},
|
|
326
|
+
0
|
|
327
|
+
);
|
|
328
|
+
let content = "";
|
|
329
|
+
let isOldVisionModel = params.model.includes("vision");
|
|
330
|
+
const functionCall = {
|
|
331
|
+
name: "",
|
|
332
|
+
args: "",
|
|
333
|
+
arguments: ""
|
|
334
|
+
};
|
|
335
|
+
for await (const chunk of iterable) {
|
|
336
|
+
const messagePart = partAsType(chunk);
|
|
337
|
+
const chatFunctionCallingPart = partAsType(chunk);
|
|
338
|
+
if (messagePart.text) {
|
|
339
|
+
if (params.tools != null) {
|
|
340
|
+
content = messagePart.text;
|
|
341
|
+
} else {
|
|
342
|
+
content += messagePart.text;
|
|
343
|
+
}
|
|
344
|
+
if (isOldVisionModel && /\s*model:\s*/.test(content)) {
|
|
345
|
+
isOldVisionModel = false;
|
|
346
|
+
content = messagePart.text.replace(/\s*model:\s*/, "");
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const deltaFunctionCall = chatFunctionCallingPart.functionCall;
|
|
350
|
+
if (deltaFunctionCall) {
|
|
351
|
+
let args = deltaFunctionCall.args?.input ?? deltaFunctionCall.args;
|
|
352
|
+
try {
|
|
353
|
+
let parsedArgs = JSON.parse(args);
|
|
354
|
+
if (typeof parsedArgs !== "string") {
|
|
355
|
+
args = parsedArgs;
|
|
356
|
+
}
|
|
357
|
+
parsedArgs = JSON.parse(args);
|
|
358
|
+
if (typeof parsedArgs !== "string") {
|
|
359
|
+
args = parsedArgs;
|
|
360
|
+
}
|
|
361
|
+
} catch (e) {
|
|
362
|
+
}
|
|
363
|
+
functionCall.args = JSON.stringify(args);
|
|
364
|
+
functionCall.name = deltaFunctionCall.name;
|
|
365
|
+
functionCall.arguments = deltaFunctionCall.args;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
const messageChunk = new import_messages2.AIMessageChunk(content);
|
|
369
|
+
messageChunk.additional_kwargs = {
|
|
370
|
+
function_call: functionCall.name.length > 0 ? {
|
|
371
|
+
name: functionCall.name,
|
|
372
|
+
arguments: functionCall.args,
|
|
373
|
+
args: functionCall.arguments
|
|
374
|
+
} : void 0
|
|
375
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
376
|
+
};
|
|
377
|
+
messageChunk.content = content;
|
|
378
|
+
const generationChunk = new import_outputs.ChatGenerationChunk({
|
|
379
|
+
message: messageChunk,
|
|
380
|
+
text: messageChunk.content
|
|
381
|
+
});
|
|
382
|
+
yield generationChunk;
|
|
383
|
+
content = messageChunk.content;
|
|
384
|
+
} catch (e) {
|
|
385
|
+
if (errorCount > 5) {
|
|
386
|
+
logger.error("error with chunk", chunk);
|
|
387
|
+
throw new import_error.ChatLunaError(
|
|
388
|
+
import_error.ChatLunaErrorCode.API_REQUEST_FAILED,
|
|
389
|
+
e
|
|
390
|
+
);
|
|
391
|
+
} else {
|
|
392
|
+
errorCount++;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} catch (e) {
|
|
398
|
+
if (e instanceof import_error.ChatLunaError) {
|
|
399
|
+
throw e;
|
|
400
|
+
} else {
|
|
401
|
+
throw new import_error.ChatLunaError(import_error.ChatLunaErrorCode.API_REQUEST_FAILED, e);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async embeddings(params) {
|
|
406
|
+
let data;
|
|
407
|
+
if (typeof params.input === "string") {
|
|
408
|
+
params.input = [params.input];
|
|
409
|
+
}
|
|
410
|
+
try {
|
|
411
|
+
const response = await this._post(
|
|
412
|
+
`models/${params.model}:batchEmbedContents`,
|
|
413
|
+
{
|
|
414
|
+
requests: params.input.map((input) => {
|
|
415
|
+
return {
|
|
416
|
+
model: `models/${params.model}`,
|
|
417
|
+
content: {
|
|
418
|
+
parts: [
|
|
419
|
+
{
|
|
420
|
+
text: input
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
data = await response.text();
|
|
429
|
+
data = JSON.parse(data);
|
|
430
|
+
if (data.embeddings && data.embeddings.length > 0) {
|
|
431
|
+
return data.embeddings.map((embedding) => {
|
|
432
|
+
return embedding.values;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
throw new Error(
|
|
436
|
+
"error when calling gemini embeddings, Result: " + JSON.stringify(data)
|
|
437
|
+
);
|
|
438
|
+
} catch (e) {
|
|
439
|
+
const error = new Error(
|
|
440
|
+
"error when calling gemini embeddings, Result: " + JSON.stringify(data)
|
|
441
|
+
);
|
|
442
|
+
error.stack = e.stack;
|
|
443
|
+
error.cause = e.cause;
|
|
444
|
+
logger.debug(e);
|
|
445
|
+
throw new import_error.ChatLunaError(import_error.ChatLunaErrorCode.API_REQUEST_FAILED, error);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async getModels() {
|
|
449
|
+
let data;
|
|
450
|
+
try {
|
|
451
|
+
const response = await this._get("models");
|
|
452
|
+
data = await response.text();
|
|
453
|
+
data = JSON.parse(data);
|
|
454
|
+
if (!data.models || !data.models.length) {
|
|
455
|
+
throw new Error(
|
|
456
|
+
"error when listing gemini models, Result:" + JSON.stringify(data)
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
return data.models.map((model) => model.name).filter(
|
|
460
|
+
(model) => model.includes("gemini") || model.includes("embedding")
|
|
461
|
+
);
|
|
462
|
+
} catch (e) {
|
|
463
|
+
const error = new Error(
|
|
464
|
+
"error when listing gemini models, Result: " + JSON.stringify(data)
|
|
465
|
+
);
|
|
466
|
+
error.stack = e.stack;
|
|
467
|
+
error.cause = e.cause;
|
|
468
|
+
throw error;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
472
|
+
_post(url, data, params = {}) {
|
|
473
|
+
const requestUrl = this._concatUrl(url);
|
|
474
|
+
for (const key in data) {
|
|
475
|
+
if (data[key] === void 0) {
|
|
476
|
+
delete data[key];
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const body = JSON.stringify(data);
|
|
480
|
+
return this._plugin.fetch(requestUrl, {
|
|
481
|
+
body,
|
|
482
|
+
headers: this._buildHeaders(),
|
|
483
|
+
method: "POST",
|
|
484
|
+
...params
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
_get(url) {
|
|
488
|
+
const requestUrl = this._concatUrl(url);
|
|
489
|
+
return this._plugin.fetch(requestUrl, {
|
|
490
|
+
method: "GET",
|
|
491
|
+
headers: this._buildHeaders()
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
_concatUrl(url) {
|
|
495
|
+
const apiEndPoint = this._config.apiEndpoint;
|
|
496
|
+
if (apiEndPoint.endsWith("/")) {
|
|
497
|
+
return apiEndPoint + url + `?key=${this._config.apiKey}`;
|
|
498
|
+
}
|
|
499
|
+
return apiEndPoint + "/" + url + `?key=${this._config.apiKey}`;
|
|
500
|
+
}
|
|
501
|
+
_buildHeaders() {
|
|
502
|
+
return {
|
|
503
|
+
/* Authorization: `Bearer ${this._config.apiKey}`, */
|
|
504
|
+
"Content-Type": "application/json"
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
async init() {
|
|
508
|
+
}
|
|
509
|
+
async dispose() {
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
// src/client.ts
|
|
514
|
+
var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient {
|
|
515
|
+
constructor(ctx, _config, clientConfig, plugin) {
|
|
516
|
+
super(ctx, clientConfig);
|
|
517
|
+
this._config = _config;
|
|
518
|
+
this._requester = new GeminiRequester(clientConfig, plugin);
|
|
519
|
+
}
|
|
520
|
+
static {
|
|
521
|
+
__name(this, "GeminiClient");
|
|
522
|
+
}
|
|
523
|
+
platform = "gemini";
|
|
524
|
+
_requester;
|
|
525
|
+
_models;
|
|
526
|
+
async init() {
|
|
527
|
+
await this.getModels();
|
|
528
|
+
}
|
|
529
|
+
async refreshModels() {
|
|
530
|
+
try {
|
|
531
|
+
const rawModels = await this._requester.getModels();
|
|
532
|
+
if (!rawModels.length) {
|
|
533
|
+
throw new import_error2.ChatLunaError(
|
|
534
|
+
import_error2.ChatLunaErrorCode.MODEL_INIT_ERROR,
|
|
535
|
+
new Error("No model found")
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
return rawModels.map((model) => model.replace("models/", "")).map((model) => {
|
|
539
|
+
return {
|
|
540
|
+
name: model,
|
|
541
|
+
maxTokens: ((model2) => {
|
|
542
|
+
if (model2.includes("gemini-1.5-pro")) {
|
|
543
|
+
return 1048576;
|
|
544
|
+
}
|
|
545
|
+
if (model2.includes("gemini-1.5-flash")) {
|
|
546
|
+
return 2097152;
|
|
547
|
+
}
|
|
548
|
+
if (model2.includes("gemini-1.0-pro")) {
|
|
549
|
+
return 30720;
|
|
550
|
+
}
|
|
551
|
+
return 30720;
|
|
552
|
+
})(model),
|
|
553
|
+
type: model.includes("embedding") ? import_types.ModelType.embeddings : import_types.ModelType.llm,
|
|
554
|
+
functionCall: !model.includes("vision"),
|
|
555
|
+
supportMode: ["all"]
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
} catch (e) {
|
|
559
|
+
throw new import_error2.ChatLunaError(import_error2.ChatLunaErrorCode.MODEL_INIT_ERROR, e);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
async getModels() {
|
|
563
|
+
if (this._models) {
|
|
564
|
+
return Object.values(this._models);
|
|
565
|
+
}
|
|
566
|
+
const models = await this.refreshModels();
|
|
567
|
+
this._models = {};
|
|
568
|
+
for (const model of models) {
|
|
569
|
+
this._models[model.name] = model;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
_createModel(model) {
|
|
573
|
+
const info = this._models[model];
|
|
574
|
+
if (info == null) {
|
|
575
|
+
throw new import_error2.ChatLunaError(import_error2.ChatLunaErrorCode.MODEL_NOT_FOUND);
|
|
576
|
+
}
|
|
577
|
+
if (info.type === import_types.ModelType.llm) {
|
|
578
|
+
return new import_model.ChatLunaChatModel({
|
|
579
|
+
modelInfo: info,
|
|
580
|
+
requester: this._requester,
|
|
581
|
+
model,
|
|
582
|
+
modelMaxContextSize: info.maxTokens,
|
|
583
|
+
maxTokens: this._config.maxTokens,
|
|
584
|
+
timeout: this._config.timeout,
|
|
585
|
+
temperature: this._config.temperature,
|
|
586
|
+
maxRetries: this._config.maxRetries,
|
|
587
|
+
llmType: "gemini"
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
return new import_model.ChatLunaEmbeddings({
|
|
591
|
+
client: this._requester,
|
|
592
|
+
model,
|
|
593
|
+
maxRetries: this._config.maxRetries
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
// src/index.ts
|
|
599
|
+
var import_logger = require("koishi-plugin-chatluna/utils/logger");
|
|
600
|
+
var logger;
|
|
601
|
+
function apply(ctx, config) {
|
|
602
|
+
const plugin = new import_chat.ChatLunaPlugin(ctx, config, "gemini");
|
|
603
|
+
logger = (0, import_logger.createLogger)(ctx, "chatluna-gemini-adapter");
|
|
604
|
+
ctx.on("ready", async () => {
|
|
605
|
+
await plugin.registerToService();
|
|
606
|
+
await plugin.parseConfig((config2) => {
|
|
607
|
+
return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
|
|
608
|
+
return {
|
|
609
|
+
apiKey,
|
|
610
|
+
apiEndpoint,
|
|
611
|
+
platform: "gemini",
|
|
612
|
+
chatLimit: config2.chatTimeLimit,
|
|
613
|
+
timeout: config2.timeout,
|
|
614
|
+
maxRetries: config2.maxRetries,
|
|
615
|
+
concurrentMaxSize: config2.chatConcurrentMaxSize
|
|
616
|
+
};
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
await plugin.registerClient(
|
|
620
|
+
(_, clientConfig) => new GeminiClient(ctx, config, clientConfig, plugin)
|
|
621
|
+
);
|
|
622
|
+
await plugin.initClients();
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
__name(apply, "apply");
|
|
626
|
+
var Config = import_koishi.Schema.intersect([
|
|
627
|
+
import_chat.ChatLunaPlugin.Config,
|
|
628
|
+
import_koishi.Schema.object({
|
|
629
|
+
apiKeys: import_koishi.Schema.array(
|
|
630
|
+
import_koishi.Schema.tuple([
|
|
631
|
+
import_koishi.Schema.string().role("secret").description("Gemini 的 API Key").required(),
|
|
632
|
+
import_koishi.Schema.string().description("请求 Gemini API 的地址").default("https://generativelanguage.googleapis.com/v1beta")
|
|
633
|
+
])
|
|
634
|
+
).description("Gemini 的 API Key 和请求地址列表").default([["", "https://generativelanguage.googleapis.com/v1beta"]])
|
|
635
|
+
}).description("请求设置"),
|
|
636
|
+
import_koishi.Schema.object({
|
|
637
|
+
maxTokens: import_koishi.Schema.number().description(
|
|
638
|
+
"回复的最大 Token 数(16~2097000,必须是16的倍数)(注意如果你目前使用的模型的最大 Token 为 8000 及以上的话才建议设置超过 512 token)"
|
|
639
|
+
).min(16).max(2097e3).step(16).default(8064),
|
|
640
|
+
temperature: import_koishi.Schema.percent().description("回复温度,越高越随机").min(0).max(1).step(0.1).default(0.8)
|
|
641
|
+
}).description("模型设置")
|
|
642
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
643
|
+
]);
|
|
644
|
+
var inject = ["chatluna"];
|
|
645
|
+
var name = "chatluna-google-gemini-adapter";
|
|
646
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
647
|
+
0 && (module.exports = {
|
|
648
|
+
Config,
|
|
649
|
+
apply,
|
|
650
|
+
inject,
|
|
651
|
+
logger,
|
|
652
|
+
name
|
|
653
|
+
});
|