koishi-plugin-aka-ai-generator 0.3.9 → 0.4.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/lib/index.js +64 -6
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -587,11 +587,31 @@ async function downloadImageAsBase643(ctx, url, timeout, logger) {
|
|
|
587
587
|
}
|
|
588
588
|
}
|
|
589
589
|
__name(downloadImageAsBase643, "downloadImageAsBase64");
|
|
590
|
-
function parseGeminiResponse(response) {
|
|
590
|
+
function parseGeminiResponse(response, logger) {
|
|
591
591
|
try {
|
|
592
592
|
const images = [];
|
|
593
|
+
if (!response) {
|
|
594
|
+
logger?.error("Gemini API 响应为空");
|
|
595
|
+
return [];
|
|
596
|
+
}
|
|
597
|
+
if (response.error) {
|
|
598
|
+
logger?.error("Gemini API 返回错误", { error: response.error });
|
|
599
|
+
throw new Error(`Gemini API 错误: ${response.error.message || JSON.stringify(response.error)}`);
|
|
600
|
+
}
|
|
593
601
|
if (response.candidates && response.candidates.length > 0) {
|
|
594
602
|
for (const candidate of response.candidates) {
|
|
603
|
+
if (candidate.finishReason && candidate.finishReason !== "STOP") {
|
|
604
|
+
logger?.warn("Gemini 响应 finishReason 异常", {
|
|
605
|
+
finishReason: candidate.finishReason,
|
|
606
|
+
safetyRatings: candidate.safetyRatings
|
|
607
|
+
});
|
|
608
|
+
if (candidate.finishReason === "SAFETY" || candidate.finishReason === "RECITATION") {
|
|
609
|
+
throw new Error(`内容被阻止: ${candidate.finishReason},可能包含不安全的内容`);
|
|
610
|
+
}
|
|
611
|
+
if (candidate.finishReason !== "MAX_TOKENS") {
|
|
612
|
+
logger?.warn("Gemini 响应可能不完整", { finishReason: candidate.finishReason });
|
|
613
|
+
}
|
|
614
|
+
}
|
|
595
615
|
if (candidate.content && candidate.content.parts) {
|
|
596
616
|
for (const part of candidate.content.parts) {
|
|
597
617
|
if (part.inlineData && part.inlineData.data) {
|
|
@@ -599,21 +619,39 @@ function parseGeminiResponse(response) {
|
|
|
599
619
|
const mimeType = part.inlineData.mimeType || "image/jpeg";
|
|
600
620
|
const dataUrl = `data:${mimeType};base64,${base64Data}`;
|
|
601
621
|
images.push(dataUrl);
|
|
622
|
+
logger?.debug("从响应中提取到图片 (inlineData)", { mimeType, dataLength: base64Data.length });
|
|
602
623
|
} else if (part.inline_data && part.inline_data.data) {
|
|
603
624
|
const base64Data = part.inline_data.data;
|
|
604
625
|
const mimeType = part.inline_data.mime_type || "image/jpeg";
|
|
605
626
|
const dataUrl = `data:${mimeType};base64,${base64Data}`;
|
|
606
627
|
images.push(dataUrl);
|
|
628
|
+
logger?.debug("从响应中提取到图片 (inline_data)", { mimeType, dataLength: base64Data.length });
|
|
607
629
|
} else if (part.fileData && part.fileData.fileUri) {
|
|
608
630
|
images.push(part.fileData.fileUri);
|
|
631
|
+
logger?.debug("从响应中提取到图片 (fileData)", { fileUri: part.fileData.fileUri });
|
|
632
|
+
} else if (part.text) {
|
|
633
|
+
logger?.warn("响应中包含文本而非图片", { text: part.text.substring(0, 100) });
|
|
609
634
|
}
|
|
610
635
|
}
|
|
636
|
+
} else {
|
|
637
|
+
logger?.warn("候选响应中没有 content.parts", { candidate: JSON.stringify(candidate).substring(0, 200) });
|
|
611
638
|
}
|
|
612
639
|
}
|
|
640
|
+
} else {
|
|
641
|
+
logger?.warn("Gemini API 响应中没有 candidates", { response: JSON.stringify(response).substring(0, 500) });
|
|
642
|
+
}
|
|
643
|
+
if (images.length === 0) {
|
|
644
|
+
logger?.error("未能从 Gemini API 响应中提取到任何图片", {
|
|
645
|
+
hasCandidates: !!response.candidates,
|
|
646
|
+
candidatesCount: response.candidates?.length || 0,
|
|
647
|
+
responseKeys: Object.keys(response),
|
|
648
|
+
firstCandidate: response.candidates?.[0] ? JSON.stringify(response.candidates[0]).substring(0, 300) : null
|
|
649
|
+
});
|
|
613
650
|
}
|
|
614
651
|
return images;
|
|
615
652
|
} catch (error) {
|
|
616
|
-
|
|
653
|
+
logger?.error("解析 Gemini 响应时出错", { error: error.message, stack: error.stack });
|
|
654
|
+
throw error;
|
|
617
655
|
}
|
|
618
656
|
}
|
|
619
657
|
__name(parseGeminiResponse, "parseGeminiResponse");
|
|
@@ -626,12 +664,18 @@ var GeminiProvider = class {
|
|
|
626
664
|
this.config = config;
|
|
627
665
|
}
|
|
628
666
|
async generateImages(prompt, imageUrls, numImages) {
|
|
629
|
-
|
|
667
|
+
let urls = [];
|
|
668
|
+
if (Array.isArray(imageUrls)) {
|
|
669
|
+
urls = imageUrls.filter((url) => url && typeof url === "string" && url.trim());
|
|
670
|
+
} else if (imageUrls && typeof imageUrls === "string" && imageUrls.trim()) {
|
|
671
|
+
urls = [imageUrls];
|
|
672
|
+
}
|
|
630
673
|
const logger = this.config.logger;
|
|
631
674
|
const ctx = this.config.ctx;
|
|
632
|
-
logger.debug("
|
|
675
|
+
logger.debug("开始处理图片输入", { urls, promptLength: prompt.length, isTextToImage: urls.length === 0 });
|
|
633
676
|
const imageParts = [];
|
|
634
677
|
for (const url of urls) {
|
|
678
|
+
if (!url || !url.trim()) continue;
|
|
635
679
|
const { data, mimeType } = await downloadImageAsBase643(
|
|
636
680
|
ctx,
|
|
637
681
|
url,
|
|
@@ -678,14 +722,24 @@ var GeminiProvider = class {
|
|
|
678
722
|
timeout: this.config.apiTimeout * 1e3
|
|
679
723
|
}
|
|
680
724
|
);
|
|
681
|
-
const images = parseGeminiResponse(response);
|
|
725
|
+
const images = parseGeminiResponse(response, logger);
|
|
726
|
+
if (images.length === 0) {
|
|
727
|
+
logger.warn("Gemini API 调用成功但未解析到图片", {
|
|
728
|
+
current: i + 1,
|
|
729
|
+
total: numImages,
|
|
730
|
+
responseHasCandidates: !!response.candidates,
|
|
731
|
+
responseKeys: Object.keys(response)
|
|
732
|
+
});
|
|
733
|
+
} else {
|
|
734
|
+
logger.success("Gemini API 调用成功", { current: i + 1, total: numImages, imagesCount: images.length });
|
|
735
|
+
}
|
|
682
736
|
allImages.push(...images);
|
|
683
|
-
logger.success("Gemini API 调用成功", { current: i + 1, total: numImages });
|
|
684
737
|
} catch (error) {
|
|
685
738
|
logger.error("Gemini API 调用失败", {
|
|
686
739
|
message: error?.message || "未知错误",
|
|
687
740
|
code: error?.code,
|
|
688
741
|
status: error?.response?.status,
|
|
742
|
+
responseData: error?.response?.data ? JSON.stringify(error.response.data).substring(0, 500) : void 0,
|
|
689
743
|
current: i + 1,
|
|
690
744
|
total: numImages
|
|
691
745
|
});
|
|
@@ -696,6 +750,10 @@ var GeminiProvider = class {
|
|
|
696
750
|
throw new Error(`图像处理API调用失败: ${error?.message || "未知错误"}`);
|
|
697
751
|
}
|
|
698
752
|
}
|
|
753
|
+
if (allImages.length === 0) {
|
|
754
|
+
logger.error("所有 Gemini API 调用都未生成图片", { numImages });
|
|
755
|
+
throw new Error("未能从 Gemini API 生成图片,请检查 prompt 和模型配置");
|
|
756
|
+
}
|
|
699
757
|
return allImages;
|
|
700
758
|
}
|
|
701
759
|
};
|