koishi-plugin-aka-ai-generator 0.5.2 → 0.5.3
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 +57 -9
- 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());
|
|
@@ -794,12 +818,20 @@ var GeminiProvider = class {
|
|
|
794
818
|
generationConfig: {
|
|
795
819
|
responseModalities: ["IMAGE"],
|
|
796
820
|
imageConfig: {
|
|
797
|
-
aspectRatio: "16:9"
|
|
798
|
-
imageSize: "4K"
|
|
821
|
+
aspectRatio: "16:9"
|
|
799
822
|
}
|
|
800
823
|
}
|
|
801
824
|
};
|
|
802
|
-
logger.debug("调用 Gemini API", {
|
|
825
|
+
logger.debug("调用 Gemini API", {
|
|
826
|
+
prompt: prompt.substring(0, 100),
|
|
827
|
+
imageCount: urls.length,
|
|
828
|
+
numImages,
|
|
829
|
+
current: i + 1,
|
|
830
|
+
endpoint,
|
|
831
|
+
hasApiKey: !!this.config.apiKey,
|
|
832
|
+
apiKeyLength: this.config.apiKey?.length || 0,
|
|
833
|
+
modelId: this.config.modelId
|
|
834
|
+
});
|
|
803
835
|
try {
|
|
804
836
|
const response = await ctx.http.post(
|
|
805
837
|
endpoint,
|
|
@@ -807,7 +839,10 @@ var GeminiProvider = class {
|
|
|
807
839
|
{
|
|
808
840
|
headers: {
|
|
809
841
|
"Content-Type": "application/json",
|
|
810
|
-
"
|
|
842
|
+
"X-Goog-Api-Key": this.config.apiKey
|
|
843
|
+
},
|
|
844
|
+
params: {
|
|
845
|
+
key: this.config.apiKey
|
|
811
846
|
},
|
|
812
847
|
timeout: this.config.apiTimeout * 1e3
|
|
813
848
|
}
|
|
@@ -827,14 +862,27 @@ var GeminiProvider = class {
|
|
|
827
862
|
} catch (error) {
|
|
828
863
|
const sanitizedError = sanitizeError(error);
|
|
829
864
|
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
830
|
-
|
|
865
|
+
const errorDetails = {
|
|
831
866
|
message: safeMessage,
|
|
832
867
|
code: error?.code,
|
|
833
868
|
status: error?.response?.status,
|
|
834
|
-
|
|
869
|
+
statusText: error?.response?.statusText,
|
|
835
870
|
current: i + 1,
|
|
836
871
|
total: numImages
|
|
837
|
-
}
|
|
872
|
+
};
|
|
873
|
+
if (error?.response?.data) {
|
|
874
|
+
try {
|
|
875
|
+
const responseStr = JSON.stringify(error.response.data);
|
|
876
|
+
errorDetails.responseData = sanitizeString(responseStr.substring(0, 1e3));
|
|
877
|
+
} catch (e) {
|
|
878
|
+
errorDetails.responseData = "无法序列化响应数据";
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (error?.config) {
|
|
882
|
+
errorDetails.url = error.config.url ? sanitizeUrl(error.config.url) : void 0;
|
|
883
|
+
errorDetails.method = error.config.method;
|
|
884
|
+
}
|
|
885
|
+
logger.error("Gemini API 调用失败", errorDetails);
|
|
838
886
|
if (allImages.length > 0) {
|
|
839
887
|
logger.warn("部分图片生成失败,返回已生成的图片", { generated: allImages.length, requested: numImages });
|
|
840
888
|
break;
|
package/lib/providers/types.d.ts
CHANGED