koishi-plugin-aka-ai-generator 0.0.2 → 0.0.4
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.d.ts +1 -0
- package/lib/index.js +161 -27
- package/lib/providers/index.d.ts +1 -0
- package/lib/providers/types.d.ts +1 -0
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -195,7 +195,9 @@ async function downloadImageAsBase642(ctx, url, timeout, logger) {
|
|
|
195
195
|
mimeType = "image/gif";
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
-
logger
|
|
198
|
+
if (logger) {
|
|
199
|
+
logger.debug("图片下载并转换为Base64", { url, mimeType, size: base64.length });
|
|
200
|
+
}
|
|
199
201
|
return { data: base64, mimeType };
|
|
200
202
|
} catch (error) {
|
|
201
203
|
logger.error("下载图片失败", { url, error });
|
|
@@ -203,14 +205,23 @@ async function downloadImageAsBase642(ctx, url, timeout, logger) {
|
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
__name(downloadImageAsBase642, "downloadImageAsBase64");
|
|
206
|
-
function parseGptGodResponse(response) {
|
|
208
|
+
function parseGptGodResponse(response, logger) {
|
|
207
209
|
try {
|
|
208
210
|
const images = [];
|
|
209
211
|
if (Array.isArray(response.images)) {
|
|
212
|
+
if (logger) {
|
|
213
|
+
logger.debug("从 response.images 数组提取图片", { count: response.images.length });
|
|
214
|
+
}
|
|
210
215
|
return response.images;
|
|
211
216
|
}
|
|
212
|
-
if (response.image && typeof response.image === "string"
|
|
213
|
-
|
|
217
|
+
if (response.image && typeof response.image === "string") {
|
|
218
|
+
if (response.image.startsWith("data:") || response.image.startsWith("http")) {
|
|
219
|
+
if (logger) {
|
|
220
|
+
logger.debug("从 response.image 提取图片");
|
|
221
|
+
}
|
|
222
|
+
images.push(response.image);
|
|
223
|
+
return images;
|
|
224
|
+
}
|
|
214
225
|
}
|
|
215
226
|
if (response?.choices?.length > 0) {
|
|
216
227
|
const firstChoice = response.choices[0];
|
|
@@ -219,33 +230,123 @@ function parseGptGodResponse(response) {
|
|
|
219
230
|
if (typeof messageContent === "string") {
|
|
220
231
|
contentText = messageContent;
|
|
221
232
|
} else if (Array.isArray(messageContent)) {
|
|
222
|
-
|
|
233
|
+
for (const part of messageContent) {
|
|
234
|
+
if (part?.type === "image_url" && part?.image_url?.url) {
|
|
235
|
+
if (logger) {
|
|
236
|
+
logger.debug("从 content 数组的 image_url 提取图片");
|
|
237
|
+
}
|
|
238
|
+
images.push(part.image_url.url);
|
|
239
|
+
} else if (part?.type === "text" && part?.text) {
|
|
240
|
+
contentText += part.text + "\n";
|
|
241
|
+
} else if (part?.text) {
|
|
242
|
+
contentText += part.text + "\n";
|
|
243
|
+
}
|
|
244
|
+
}
|
|
223
245
|
} else if (messageContent?.text) {
|
|
224
246
|
contentText = messageContent.text;
|
|
225
247
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
while ((match = mdImageRegex.exec(contentText)) !== null) {
|
|
229
|
-
images.push(match[1]);
|
|
248
|
+
if (images.length > 0) {
|
|
249
|
+
return images;
|
|
230
250
|
}
|
|
231
|
-
if (
|
|
232
|
-
const
|
|
233
|
-
let
|
|
234
|
-
while ((
|
|
235
|
-
images.push(
|
|
251
|
+
if (contentText) {
|
|
252
|
+
const mdImageRegex = /!\[.*?\]\((https?:\/\/[^\)]+)\)/g;
|
|
253
|
+
let match;
|
|
254
|
+
while ((match = mdImageRegex.exec(contentText)) !== null) {
|
|
255
|
+
images.push(match[1]);
|
|
256
|
+
}
|
|
257
|
+
if (images.length === 0) {
|
|
258
|
+
const urlRegex = /(https?:\/\/[^\s"')<>]+\.(?:png|jpg|jpeg|webp|gif|bmp))/gi;
|
|
259
|
+
let urlMatch;
|
|
260
|
+
while ((urlMatch = urlRegex.exec(contentText)) !== null) {
|
|
261
|
+
images.push(urlMatch[1]);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (images.length === 0 && contentText.trim().startsWith("http")) {
|
|
265
|
+
const trimmedUrl = contentText.trim().split(/\s/)[0];
|
|
266
|
+
if (trimmedUrl.match(/^https?:\/\//)) {
|
|
267
|
+
images.push(trimmedUrl);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const dataUrlRegex = /(data:image\/[^;]+;base64,[^\s"')<>]+)/gi;
|
|
271
|
+
let dataUrlMatch;
|
|
272
|
+
while ((dataUrlMatch = dataUrlRegex.exec(contentText)) !== null) {
|
|
273
|
+
images.push(dataUrlMatch[1]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (images.length === 0 && firstChoice.message) {
|
|
277
|
+
if (firstChoice.message.image_url) {
|
|
278
|
+
if (logger) {
|
|
279
|
+
logger.debug("从 message.image_url 提取图片");
|
|
280
|
+
}
|
|
281
|
+
images.push(firstChoice.message.image_url);
|
|
282
|
+
}
|
|
283
|
+
if (Array.isArray(firstChoice.message.images)) {
|
|
284
|
+
if (logger) {
|
|
285
|
+
logger.debug("从 message.images 数组提取图片", { count: firstChoice.message.images.length });
|
|
286
|
+
}
|
|
287
|
+
return firstChoice.message.images;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (images.length === 0) {
|
|
292
|
+
if (response.data) {
|
|
293
|
+
if (Array.isArray(response.data)) {
|
|
294
|
+
const dataImages = response.data.filter(
|
|
295
|
+
(item) => item?.url || item?.image_url || typeof item === "string" && (item.startsWith("http") || item.startsWith("data:"))
|
|
296
|
+
).map((item) => item?.url || item?.image_url || item);
|
|
297
|
+
if (dataImages.length > 0) {
|
|
298
|
+
if (logger) {
|
|
299
|
+
logger.debug("从 response.data 数组提取图片", { count: dataImages.length });
|
|
300
|
+
}
|
|
301
|
+
return dataImages;
|
|
302
|
+
}
|
|
303
|
+
} else if (response.data.url || response.data.image_url) {
|
|
304
|
+
if (logger) {
|
|
305
|
+
logger.debug("从 response.data 提取图片");
|
|
306
|
+
}
|
|
307
|
+
images.push(response.data.url || response.data.image_url);
|
|
236
308
|
}
|
|
237
309
|
}
|
|
238
|
-
if (
|
|
239
|
-
|
|
310
|
+
if (response.result) {
|
|
311
|
+
if (Array.isArray(response.result)) {
|
|
312
|
+
const resultImages = response.result.filter(
|
|
313
|
+
(item) => item?.url || item?.image_url || typeof item === "string" && (item.startsWith("http") || item.startsWith("data:"))
|
|
314
|
+
).map((item) => item?.url || item?.image_url || item);
|
|
315
|
+
if (resultImages.length > 0) {
|
|
316
|
+
if (logger) {
|
|
317
|
+
logger.debug("从 response.result 数组提取图片", { count: resultImages.length });
|
|
318
|
+
}
|
|
319
|
+
return resultImages;
|
|
320
|
+
}
|
|
321
|
+
} else if (typeof response.result === "string" && (response.result.startsWith("http") || response.result.startsWith("data:"))) {
|
|
322
|
+
if (logger) {
|
|
323
|
+
logger.debug("从 response.result 提取图片");
|
|
324
|
+
}
|
|
325
|
+
images.push(response.result);
|
|
326
|
+
}
|
|
240
327
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
images.
|
|
328
|
+
}
|
|
329
|
+
if (images.length > 0) {
|
|
330
|
+
if (logger) {
|
|
331
|
+
logger.debug("成功提取图片", { count: images.length });
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
if (logger) {
|
|
335
|
+
logger.warn("未能从响应中提取图片", {
|
|
336
|
+
responseStructure: {
|
|
337
|
+
hasChoices: !!response?.choices,
|
|
338
|
+
hasImages: !!response?.images,
|
|
339
|
+
hasImage: !!response?.image,
|
|
340
|
+
hasData: !!response?.data,
|
|
341
|
+
hasResult: !!response?.result,
|
|
342
|
+
keys: Object.keys(response || {})
|
|
343
|
+
}
|
|
344
|
+
});
|
|
245
345
|
}
|
|
246
346
|
}
|
|
247
347
|
return images;
|
|
248
348
|
} catch (error) {
|
|
349
|
+
logger?.error("解析响应时出错", { error });
|
|
249
350
|
return [];
|
|
250
351
|
}
|
|
251
352
|
}
|
|
@@ -265,7 +366,9 @@ var GptGodProvider = class {
|
|
|
265
366
|
if (!this.config.apiKey) {
|
|
266
367
|
throw new Error("GPTGod 配置不完整,请检查 API Key");
|
|
267
368
|
}
|
|
268
|
-
|
|
369
|
+
if (this.config.logLevel === "debug") {
|
|
370
|
+
logger.debug("调用 GPTGod 图像编辑 API", { prompt, imageCount: urls.length, numImages });
|
|
371
|
+
}
|
|
269
372
|
const contentParts = [
|
|
270
373
|
{
|
|
271
374
|
type: "text",
|
|
@@ -312,9 +415,26 @@ var GptGodProvider = class {
|
|
|
312
415
|
}
|
|
313
416
|
);
|
|
314
417
|
logger.success("GPTGod 图像编辑 API 调用成功");
|
|
315
|
-
|
|
418
|
+
if (this.config.logLevel === "debug") {
|
|
419
|
+
logger.debug("GPTGod API 响应结构", {
|
|
420
|
+
hasChoices: !!response?.choices,
|
|
421
|
+
choicesLength: response?.choices?.length,
|
|
422
|
+
hasImages: !!response?.images,
|
|
423
|
+
hasImage: !!response?.image,
|
|
424
|
+
responseKeys: Object.keys(response || {}),
|
|
425
|
+
firstChoiceContent: response?.choices?.[0]?.message?.content ? typeof response.choices[0].message.content === "string" ? response.choices[0].message.content.substring(0, 200) : JSON.stringify(response.choices[0].message.content).substring(0, 200) : "none"
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const images = parseGptGodResponse(response, this.config.logLevel === "debug" ? logger : null);
|
|
316
429
|
if (images.length < numImages) {
|
|
317
|
-
|
|
430
|
+
const warnData = {
|
|
431
|
+
requested: numImages,
|
|
432
|
+
received: images.length
|
|
433
|
+
};
|
|
434
|
+
if (this.config.logLevel === "debug") {
|
|
435
|
+
warnData.responsePreview = JSON.stringify(response).substring(0, 500);
|
|
436
|
+
}
|
|
437
|
+
logger.warn("生成的图片数量不足", warnData);
|
|
318
438
|
}
|
|
319
439
|
return images;
|
|
320
440
|
} catch (error) {
|
|
@@ -337,6 +457,7 @@ function createImageProvider(config) {
|
|
|
337
457
|
apiKey: config.yunwuApiKey,
|
|
338
458
|
modelId: config.yunwuModelId,
|
|
339
459
|
apiTimeout: config.apiTimeout,
|
|
460
|
+
logLevel: config.logLevel,
|
|
340
461
|
logger: config.logger,
|
|
341
462
|
ctx: config.ctx
|
|
342
463
|
});
|
|
@@ -345,6 +466,7 @@ function createImageProvider(config) {
|
|
|
345
466
|
apiKey: config.gptgodApiKey,
|
|
346
467
|
modelId: config.gptgodModelId,
|
|
347
468
|
apiTimeout: config.apiTimeout,
|
|
469
|
+
logLevel: config.logLevel,
|
|
348
470
|
logger: config.logger,
|
|
349
471
|
ctx: config.ctx
|
|
350
472
|
});
|
|
@@ -384,7 +506,12 @@ var Config = import_koishi.Schema.intersect([
|
|
|
384
506
|
rateLimitWindow: import_koishi.Schema.number().default(300).min(60).max(3600).description("限流时间窗口(秒)"),
|
|
385
507
|
rateLimitMax: import_koishi.Schema.number().default(3).min(1).max(20).description("限流窗口内最大调用次数"),
|
|
386
508
|
// 管理员设置
|
|
387
|
-
adminUsers: import_koishi.Schema.array(import_koishi.Schema.string()).default([]).description("管理员用户ID列表(不受每日使用限制)")
|
|
509
|
+
adminUsers: import_koishi.Schema.array(import_koishi.Schema.string()).default([]).description("管理员用户ID列表(不受每日使用限制)"),
|
|
510
|
+
// 日志级别设置
|
|
511
|
+
logLevel: import_koishi.Schema.union([
|
|
512
|
+
import_koishi.Schema.const("info").description("普通信息"),
|
|
513
|
+
import_koishi.Schema.const("debug").description("完整的debug信息")
|
|
514
|
+
]).default("info").description("日志输出详细程度")
|
|
388
515
|
}),
|
|
389
516
|
// 自定义风格命令配置
|
|
390
517
|
import_koishi.Schema.object({
|
|
@@ -432,6 +559,7 @@ function apply(ctx, config) {
|
|
|
432
559
|
gptgodApiKey: config.gptgodApiKey,
|
|
433
560
|
gptgodModelId: config.gptgodModelId,
|
|
434
561
|
apiTimeout: config.apiTimeout,
|
|
562
|
+
logLevel: config.logLevel,
|
|
435
563
|
logger,
|
|
436
564
|
ctx
|
|
437
565
|
});
|
|
@@ -688,7 +816,9 @@ function apply(ctx, config) {
|
|
|
688
816
|
if (img) {
|
|
689
817
|
url = img.attrs?.src || null;
|
|
690
818
|
if (url) {
|
|
691
|
-
|
|
819
|
+
if (config.logLevel === "debug") {
|
|
820
|
+
logger.debug("从命令参数获取图片", { url });
|
|
821
|
+
}
|
|
692
822
|
return url;
|
|
693
823
|
}
|
|
694
824
|
}
|
|
@@ -701,7 +831,9 @@ function apply(ctx, config) {
|
|
|
701
831
|
return null;
|
|
702
832
|
}
|
|
703
833
|
url = images2[0].attrs.src;
|
|
704
|
-
|
|
834
|
+
if (config.logLevel === "debug") {
|
|
835
|
+
logger.debug("从引用消息获取图片", { url });
|
|
836
|
+
}
|
|
705
837
|
return url;
|
|
706
838
|
}
|
|
707
839
|
}
|
|
@@ -722,7 +854,9 @@ function apply(ctx, config) {
|
|
|
722
854
|
return null;
|
|
723
855
|
}
|
|
724
856
|
url = images[0].attrs.src;
|
|
725
|
-
|
|
857
|
+
if (config.logLevel === "debug") {
|
|
858
|
+
logger.debug("从用户输入获取图片", { url });
|
|
859
|
+
}
|
|
726
860
|
return url;
|
|
727
861
|
}
|
|
728
862
|
__name(getImageUrl, "getImageUrl");
|
package/lib/providers/index.d.ts
CHANGED
package/lib/providers/types.d.ts
CHANGED