koishi-plugin-aka-ai-generator 0.5.2 → 0.5.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.js +64 -12
- package/lib/providers/types.d.ts +4 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -42,10 +42,14 @@ function sanitizeError(error) {
|
|
|
42
42
|
const sanitized = {};
|
|
43
43
|
for (const key in error) {
|
|
44
44
|
const lowerKey = key.toLowerCase();
|
|
45
|
-
if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey
|
|
45
|
+
if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey === "key" || lowerKey === "authorization" || lowerKey === "token" || lowerKey === "secret" || lowerKey === "password" || lowerKey === "x-goog-api-key") {
|
|
46
46
|
sanitized[key] = "[REDACTED]";
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
|
+
if (lowerKey === "url" && typeof error[key] === "string") {
|
|
50
|
+
sanitized[key] = sanitizeUrl(error[key]);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
49
53
|
sanitized[key] = sanitizeError(error[key]);
|
|
50
54
|
}
|
|
51
55
|
return sanitized;
|
|
@@ -55,9 +59,26 @@ function sanitizeError(error) {
|
|
|
55
59
|
__name(sanitizeError, "sanitizeError");
|
|
56
60
|
function sanitizeString(str) {
|
|
57
61
|
if (typeof str !== "string") return str;
|
|
58
|
-
|
|
62
|
+
let sanitized = str.replace(/[?&]key=[^&\s"']+/gi, "?key=[REDACTED]").replace(/[?&]apikey=[^&\s"']+/gi, "&apikey=[REDACTED]").replace(/[?&]api_key=[^&\s"']+/gi, "&api_key=[REDACTED]");
|
|
63
|
+
sanitized = sanitized.replace(/key["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'key="[REDACTED]"').replace(/apikey["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'apikey="[REDACTED]"').replace(/api_key["\s:=]+([a-zA-Z0-9_-]{20,})/gi, 'api_key="[REDACTED]"').replace(/authorization["\s:=]+(Bearer\s+)?([a-zA-Z0-9_-]{20,})/gi, 'authorization="[REDACTED]"').replace(/Bearer\s+([a-zA-Z0-9_-]{20,})/gi, "Bearer [REDACTED]").replace(/x-goog-api-key["\s:]+([a-zA-Z0-9_-]{20,})/gi, "x-goog-api-key: [REDACTED]").replace(/X-Goog-Api-Key["\s:]+([a-zA-Z0-9_-]{20,})/gi, "X-Goog-Api-Key: [REDACTED]");
|
|
64
|
+
return sanitized;
|
|
59
65
|
}
|
|
60
66
|
__name(sanitizeString, "sanitizeString");
|
|
67
|
+
function sanitizeUrl(url) {
|
|
68
|
+
if (typeof url !== "string") return url;
|
|
69
|
+
try {
|
|
70
|
+
const urlObj = new URL(url);
|
|
71
|
+
urlObj.searchParams.delete("key");
|
|
72
|
+
urlObj.searchParams.delete("apikey");
|
|
73
|
+
urlObj.searchParams.delete("api_key");
|
|
74
|
+
urlObj.searchParams.delete("token");
|
|
75
|
+
urlObj.searchParams.delete("secret");
|
|
76
|
+
return urlObj.toString();
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return sanitizeString(url);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
__name(sanitizeUrl, "sanitizeUrl");
|
|
61
82
|
|
|
62
83
|
// src/providers/yunwu.ts
|
|
63
84
|
async function downloadImageAsBase64(ctx, url, timeout, logger) {
|
|
@@ -752,6 +773,9 @@ var GeminiProvider = class {
|
|
|
752
773
|
this.config = config;
|
|
753
774
|
}
|
|
754
775
|
async generateImages(prompt, imageUrls, numImages) {
|
|
776
|
+
if (!this.config.apiKey || !this.config.apiKey.trim()) {
|
|
777
|
+
throw new Error("Gemini API key 未配置或为空");
|
|
778
|
+
}
|
|
755
779
|
let urls = [];
|
|
756
780
|
if (Array.isArray(imageUrls)) {
|
|
757
781
|
urls = imageUrls.filter((url) => url && typeof url === "string" && url.trim());
|
|
@@ -784,7 +808,6 @@ var GeminiProvider = class {
|
|
|
784
808
|
const requestData = {
|
|
785
809
|
contents: [
|
|
786
810
|
{
|
|
787
|
-
role: "user",
|
|
788
811
|
parts: [
|
|
789
812
|
{ text: prompt },
|
|
790
813
|
...imageParts
|
|
@@ -794,20 +817,30 @@ var GeminiProvider = class {
|
|
|
794
817
|
generationConfig: {
|
|
795
818
|
responseModalities: ["IMAGE"],
|
|
796
819
|
imageConfig: {
|
|
797
|
-
aspectRatio: "16:9"
|
|
798
|
-
imageSize: "4K"
|
|
820
|
+
aspectRatio: "16:9"
|
|
799
821
|
}
|
|
800
822
|
}
|
|
801
823
|
};
|
|
802
|
-
logger.debug("调用 Gemini API", {
|
|
824
|
+
logger.debug("调用 Gemini API", {
|
|
825
|
+
prompt: prompt.substring(0, 100),
|
|
826
|
+
imageCount: urls.length,
|
|
827
|
+
numImages,
|
|
828
|
+
current: i + 1,
|
|
829
|
+
endpoint,
|
|
830
|
+
hasApiKey: !!this.config.apiKey,
|
|
831
|
+
apiKeyLength: this.config.apiKey?.length || 0,
|
|
832
|
+
modelId: this.config.modelId
|
|
833
|
+
});
|
|
803
834
|
try {
|
|
804
835
|
const response = await ctx.http.post(
|
|
805
836
|
endpoint,
|
|
806
837
|
requestData,
|
|
807
838
|
{
|
|
808
839
|
headers: {
|
|
809
|
-
"Content-Type": "application/json"
|
|
810
|
-
|
|
840
|
+
"Content-Type": "application/json"
|
|
841
|
+
},
|
|
842
|
+
params: {
|
|
843
|
+
key: this.config.apiKey
|
|
811
844
|
},
|
|
812
845
|
timeout: this.config.apiTimeout * 1e3
|
|
813
846
|
}
|
|
@@ -827,14 +860,33 @@ var GeminiProvider = class {
|
|
|
827
860
|
} catch (error) {
|
|
828
861
|
const sanitizedError = sanitizeError(error);
|
|
829
862
|
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
830
|
-
|
|
863
|
+
const errorDetails = {
|
|
831
864
|
message: safeMessage,
|
|
832
865
|
code: error?.code,
|
|
833
866
|
status: error?.response?.status,
|
|
834
|
-
|
|
867
|
+
statusText: error?.response?.statusText,
|
|
835
868
|
current: i + 1,
|
|
836
|
-
total: numImages
|
|
837
|
-
|
|
869
|
+
total: numImages,
|
|
870
|
+
errorType: error?.name || error?.constructor?.name || "Unknown"
|
|
871
|
+
};
|
|
872
|
+
if (error?.response?.data) {
|
|
873
|
+
try {
|
|
874
|
+
const responseStr = JSON.stringify(error.response.data);
|
|
875
|
+
errorDetails.responseData = sanitizeString(responseStr.substring(0, 1e3));
|
|
876
|
+
} catch (e) {
|
|
877
|
+
errorDetails.responseData = "无法序列化响应数据";
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (error?.config) {
|
|
881
|
+
errorDetails.url = error.config.url ? sanitizeUrl(error.config.url) : void 0;
|
|
882
|
+
errorDetails.method = error.config.method;
|
|
883
|
+
errorDetails.hasData = !!error.config.data;
|
|
884
|
+
}
|
|
885
|
+
if (error?.code === "ECONNREFUSED" || error?.code === "ETIMEDOUT" || error?.code === "ENOTFOUND") {
|
|
886
|
+
errorDetails.networkError = true;
|
|
887
|
+
errorDetails.networkErrorCode = error.code;
|
|
888
|
+
}
|
|
889
|
+
logger.error("Gemini API 调用失败", errorDetails);
|
|
838
890
|
if (allImages.length > 0) {
|
|
839
891
|
logger.warn("部分图片生成失败,返回已生成的图片", { generated: allImages.length, requested: numImages });
|
|
840
892
|
break;
|
package/lib/providers/types.d.ts
CHANGED