koishi-plugin-aka-ai-generator 0.4.2 → 0.5.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.d.ts +2 -0
- package/lib/index.js +178 -32
- package/lib/providers/types.d.ts +8 -0
- package/package.json +9 -1
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -29,6 +29,36 @@ var import_koishi = require("koishi");
|
|
|
29
29
|
var import_fs = require("fs");
|
|
30
30
|
var import_path = require("path");
|
|
31
31
|
|
|
32
|
+
// src/providers/types.ts
|
|
33
|
+
function sanitizeError(error) {
|
|
34
|
+
if (!error) return error;
|
|
35
|
+
if (typeof error === "string") {
|
|
36
|
+
return sanitizeString(error);
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(error)) {
|
|
39
|
+
return error.map((item) => sanitizeError(item));
|
|
40
|
+
}
|
|
41
|
+
if (typeof error === "object") {
|
|
42
|
+
const sanitized = {};
|
|
43
|
+
for (const key in error) {
|
|
44
|
+
const lowerKey = key.toLowerCase();
|
|
45
|
+
if (lowerKey.includes("apikey") || lowerKey.includes("api_key") || lowerKey.includes("apikey") || lowerKey === "key" || lowerKey === "authorization" || lowerKey === "token" || lowerKey === "secret" || lowerKey === "password") {
|
|
46
|
+
sanitized[key] = "[REDACTED]";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
sanitized[key] = sanitizeError(error[key]);
|
|
50
|
+
}
|
|
51
|
+
return sanitized;
|
|
52
|
+
}
|
|
53
|
+
return error;
|
|
54
|
+
}
|
|
55
|
+
__name(sanitizeError, "sanitizeError");
|
|
56
|
+
function sanitizeString(str) {
|
|
57
|
+
if (typeof str !== "string") return str;
|
|
58
|
+
return str.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]");
|
|
59
|
+
}
|
|
60
|
+
__name(sanitizeString, "sanitizeString");
|
|
61
|
+
|
|
32
62
|
// src/providers/yunwu.ts
|
|
33
63
|
async function downloadImageAsBase64(ctx, url, timeout, logger) {
|
|
34
64
|
try {
|
|
@@ -148,8 +178,9 @@ var YunwuProvider = class {
|
|
|
148
178
|
allImages.push(...images);
|
|
149
179
|
logger.success("云雾图像编辑 API 调用成功", { current: i + 1, total: numImages });
|
|
150
180
|
} catch (error) {
|
|
181
|
+
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
151
182
|
logger.error("云雾图像编辑 API 调用失败", {
|
|
152
|
-
message:
|
|
183
|
+
message: safeMessage,
|
|
153
184
|
code: error?.code,
|
|
154
185
|
status: error?.response?.status,
|
|
155
186
|
current: i + 1,
|
|
@@ -516,23 +547,25 @@ var GptGodProvider = class {
|
|
|
516
547
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
517
548
|
continue;
|
|
518
549
|
}
|
|
550
|
+
const sanitizedError = sanitizeError(error);
|
|
551
|
+
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
519
552
|
logger.error("GPTGod 图像编辑 API 调用失败", {
|
|
520
|
-
message:
|
|
553
|
+
message: safeMessage,
|
|
521
554
|
name: error?.name,
|
|
522
555
|
code: error?.code,
|
|
523
556
|
status: error?.response?.status,
|
|
524
557
|
statusText: error?.response?.statusText,
|
|
525
|
-
data: error?.response?.data,
|
|
526
|
-
stack: error?.stack,
|
|
527
|
-
cause: error?.cause,
|
|
558
|
+
data: sanitizeError(error?.response?.data),
|
|
559
|
+
stack: sanitizeString(error?.stack || ""),
|
|
560
|
+
cause: sanitizeError(error?.cause),
|
|
528
561
|
attempt,
|
|
529
562
|
maxRetries,
|
|
530
563
|
current: i + 1,
|
|
531
564
|
total: numImages,
|
|
532
|
-
// 如果是 axios 错误,通常会有 config 和 request
|
|
565
|
+
// 如果是 axios 错误,通常会有 config 和 request 信息(清理敏感信息)
|
|
533
566
|
url: error?.config?.url,
|
|
534
567
|
method: error?.config?.method,
|
|
535
|
-
headers: error?.config?.headers
|
|
568
|
+
headers: sanitizeError(error?.config?.headers)
|
|
536
569
|
});
|
|
537
570
|
if (error?.cause?.code === "UND_ERR_SOCKET" || error?.message?.includes("other side closed")) {
|
|
538
571
|
throw new Error("图像处理失败:服务器连接中断,可能是服务器负载过高或网络不稳定,请稍后重试");
|
|
@@ -595,8 +628,11 @@ function parseGeminiResponse(response, logger) {
|
|
|
595
628
|
return [];
|
|
596
629
|
}
|
|
597
630
|
if (response.error) {
|
|
598
|
-
|
|
599
|
-
|
|
631
|
+
const sanitizedError = sanitizeError(response.error);
|
|
632
|
+
logger?.error("Gemini API 返回错误", { error: sanitizedError });
|
|
633
|
+
const errorMessage = response.error.message || JSON.stringify(sanitizedError);
|
|
634
|
+
const safeMessage = sanitizeString(errorMessage);
|
|
635
|
+
throw new Error(`Gemini API 错误: ${safeMessage}`);
|
|
600
636
|
}
|
|
601
637
|
if (response.promptFeedback) {
|
|
602
638
|
const blockReason = response.promptFeedback.blockReason;
|
|
@@ -698,8 +734,12 @@ function parseGeminiResponse(response, logger) {
|
|
|
698
734
|
}
|
|
699
735
|
return images;
|
|
700
736
|
} catch (error) {
|
|
701
|
-
|
|
702
|
-
|
|
737
|
+
const safeMessage = sanitizeString(error?.message || "未知错误");
|
|
738
|
+
const safeStack = sanitizeString(error?.stack || "");
|
|
739
|
+
logger?.error("解析 Gemini 响应时出错", { error: safeMessage, stack: safeStack });
|
|
740
|
+
const sanitizedError = new Error(safeMessage);
|
|
741
|
+
sanitizedError.name = error?.name || "Error";
|
|
742
|
+
throw sanitizedError;
|
|
703
743
|
}
|
|
704
744
|
}
|
|
705
745
|
__name(parseGeminiResponse, "parseGeminiResponse");
|
|
@@ -783,11 +823,13 @@ var GeminiProvider = class {
|
|
|
783
823
|
}
|
|
784
824
|
allImages.push(...images);
|
|
785
825
|
} catch (error) {
|
|
826
|
+
const sanitizedError = sanitizeError(error);
|
|
827
|
+
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
786
828
|
logger.error("Gemini API 调用失败", {
|
|
787
|
-
message:
|
|
829
|
+
message: safeMessage,
|
|
788
830
|
code: error?.code,
|
|
789
831
|
status: error?.response?.status,
|
|
790
|
-
responseData: error?.response?.data ? JSON.stringify(error.response.data).substring(0, 500) : void 0,
|
|
832
|
+
responseData: error?.response?.data ? sanitizeString(JSON.stringify(error.response.data).substring(0, 500)) : void 0,
|
|
791
833
|
current: i + 1,
|
|
792
834
|
total: numImages
|
|
793
835
|
});
|
|
@@ -795,7 +837,7 @@ var GeminiProvider = class {
|
|
|
795
837
|
logger.warn("部分图片生成失败,返回已生成的图片", { generated: allImages.length, requested: numImages });
|
|
796
838
|
break;
|
|
797
839
|
}
|
|
798
|
-
throw new Error(`图像处理API调用失败: ${
|
|
840
|
+
throw new Error(`图像处理API调用失败: ${safeMessage}`);
|
|
799
841
|
}
|
|
800
842
|
}
|
|
801
843
|
if (allImages.length === 0) {
|
|
@@ -1122,7 +1164,7 @@ function apply(ctx, config) {
|
|
|
1122
1164
|
rateLimitMap.set(userId, userTimestamps);
|
|
1123
1165
|
}
|
|
1124
1166
|
__name(updateRateLimit, "updateRateLimit");
|
|
1125
|
-
async function checkDailyLimit(userId, numImages = 1) {
|
|
1167
|
+
async function checkDailyLimit(userId, numImages = 1, updateRateLimitImmediately = true) {
|
|
1126
1168
|
if (isAdmin(userId)) {
|
|
1127
1169
|
return { allowed: true, isAdmin: true };
|
|
1128
1170
|
}
|
|
@@ -1130,6 +1172,9 @@ function apply(ctx, config) {
|
|
|
1130
1172
|
if (!rateLimitCheck.allowed) {
|
|
1131
1173
|
return { ...rateLimitCheck, isAdmin: false };
|
|
1132
1174
|
}
|
|
1175
|
+
if (updateRateLimitImmediately) {
|
|
1176
|
+
updateRateLimit(userId);
|
|
1177
|
+
}
|
|
1133
1178
|
const usersData = await loadUsersData();
|
|
1134
1179
|
const userData = usersData[userId];
|
|
1135
1180
|
if (!userData) {
|
|
@@ -1162,6 +1207,46 @@ function apply(ctx, config) {
|
|
|
1162
1207
|
return { allowed: true, isAdmin: false };
|
|
1163
1208
|
}
|
|
1164
1209
|
__name(checkDailyLimit, "checkDailyLimit");
|
|
1210
|
+
function isSafetyBlockError(error) {
|
|
1211
|
+
if (!error) return false;
|
|
1212
|
+
const errorMessage = typeof error === "string" ? error : error?.message || "";
|
|
1213
|
+
if (!errorMessage) return false;
|
|
1214
|
+
const lowerMessage = errorMessage.toLowerCase();
|
|
1215
|
+
const safetyKeywords = [
|
|
1216
|
+
"安全策略",
|
|
1217
|
+
"被阻止",
|
|
1218
|
+
"被拦截",
|
|
1219
|
+
"blocked",
|
|
1220
|
+
"safety",
|
|
1221
|
+
"prohibited",
|
|
1222
|
+
"recitation",
|
|
1223
|
+
"内容被阻止",
|
|
1224
|
+
"内容被拦截",
|
|
1225
|
+
"安全策略阻止",
|
|
1226
|
+
"安全策略拦截"
|
|
1227
|
+
];
|
|
1228
|
+
return safetyKeywords.some((keyword) => lowerMessage.includes(keyword.toLowerCase()));
|
|
1229
|
+
}
|
|
1230
|
+
__name(isSafetyBlockError, "isSafetyBlockError");
|
|
1231
|
+
async function checkSafetyBlockLimit(userId) {
|
|
1232
|
+
const usersData = await loadUsersData();
|
|
1233
|
+
const userData = usersData[userId];
|
|
1234
|
+
if (!userData || !userData.safetyBlockHistory || userData.safetyBlockHistory.length === 0) {
|
|
1235
|
+
return { allowed: true };
|
|
1236
|
+
}
|
|
1237
|
+
const windowSize = 10;
|
|
1238
|
+
const recentBlocks = userData.safetyBlockHistory.slice(-windowSize);
|
|
1239
|
+
const blockRate = recentBlocks.length / windowSize;
|
|
1240
|
+
const threshold = 0.5;
|
|
1241
|
+
if (blockRate > threshold) {
|
|
1242
|
+
return {
|
|
1243
|
+
allowed: false,
|
|
1244
|
+
message: `检测到您最近多次发送被安全策略拦截的内容(拦截率:${(blockRate * 100).toFixed(0)}%),请检查您的内容是否符合使用规范。如继续发送违规内容,可能会被进一步限制。`
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
return { allowed: true };
|
|
1248
|
+
}
|
|
1249
|
+
__name(checkSafetyBlockLimit, "checkSafetyBlockLimit");
|
|
1165
1250
|
async function getPromptInput(session, message) {
|
|
1166
1251
|
await session.send(message);
|
|
1167
1252
|
const input = await session.prompt(3e4);
|
|
@@ -1241,15 +1326,24 @@ function apply(ctx, config) {
|
|
|
1241
1326
|
donationCount: 0,
|
|
1242
1327
|
donationAmount: 0,
|
|
1243
1328
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1244
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1329
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1330
|
+
safetyBlockCount: 0,
|
|
1331
|
+
safetyBlockHistory: []
|
|
1245
1332
|
};
|
|
1246
1333
|
await saveUsersData(usersData);
|
|
1247
1334
|
logger.info("创建新用户数据", { userId, userName });
|
|
1335
|
+
} else {
|
|
1336
|
+
if (usersData[userId].safetyBlockCount === void 0) {
|
|
1337
|
+
usersData[userId].safetyBlockCount = 0;
|
|
1338
|
+
}
|
|
1339
|
+
if (usersData[userId].safetyBlockHistory === void 0) {
|
|
1340
|
+
usersData[userId].safetyBlockHistory = [];
|
|
1341
|
+
}
|
|
1248
1342
|
}
|
|
1249
1343
|
return usersData[userId];
|
|
1250
1344
|
}
|
|
1251
1345
|
__name(getUserData, "getUserData");
|
|
1252
|
-
async function updateUserData(userId, userName, commandName, numImages = 1) {
|
|
1346
|
+
async function updateUserData(userId, userName, commandName, numImages = 1, isSafetyBlock = false) {
|
|
1253
1347
|
const usersData = await loadUsersData();
|
|
1254
1348
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1255
1349
|
const today = (/* @__PURE__ */ new Date()).toDateString();
|
|
@@ -1265,11 +1359,19 @@ function apply(ctx, config) {
|
|
|
1265
1359
|
donationCount: 0,
|
|
1266
1360
|
donationAmount: 0,
|
|
1267
1361
|
lastUsed: now,
|
|
1268
|
-
createdAt: now
|
|
1362
|
+
createdAt: now,
|
|
1363
|
+
safetyBlockCount: isSafetyBlock ? numImages : 0,
|
|
1364
|
+
safetyBlockHistory: isSafetyBlock ? [now] : []
|
|
1269
1365
|
};
|
|
1270
1366
|
await saveUsersData(usersData);
|
|
1271
1367
|
return { userData: usersData[userId], consumptionType: "free", freeUsed: numImages, purchasedUsed: 0 };
|
|
1272
1368
|
}
|
|
1369
|
+
if (usersData[userId].safetyBlockCount === void 0) {
|
|
1370
|
+
usersData[userId].safetyBlockCount = 0;
|
|
1371
|
+
}
|
|
1372
|
+
if (usersData[userId].safetyBlockHistory === void 0) {
|
|
1373
|
+
usersData[userId].safetyBlockHistory = [];
|
|
1374
|
+
}
|
|
1273
1375
|
usersData[userId].totalUsageCount += numImages;
|
|
1274
1376
|
usersData[userId].lastUsed = now;
|
|
1275
1377
|
const lastReset = new Date(usersData[userId].lastDailyReset || usersData[userId].createdAt).toDateString();
|
|
@@ -1293,6 +1395,13 @@ function apply(ctx, config) {
|
|
|
1293
1395
|
purchasedUsed = purchasedToUse;
|
|
1294
1396
|
remainingToConsume -= purchasedToUse;
|
|
1295
1397
|
}
|
|
1398
|
+
if (isSafetyBlock) {
|
|
1399
|
+
usersData[userId].safetyBlockCount += numImages;
|
|
1400
|
+
usersData[userId].safetyBlockHistory.push(now);
|
|
1401
|
+
if (usersData[userId].safetyBlockHistory.length > 20) {
|
|
1402
|
+
usersData[userId].safetyBlockHistory = usersData[userId].safetyBlockHistory.slice(-20);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1296
1405
|
await saveUsersData(usersData);
|
|
1297
1406
|
let consumptionType;
|
|
1298
1407
|
if (freeUsed > 0 && purchasedUsed > 0) {
|
|
@@ -1305,17 +1414,17 @@ function apply(ctx, config) {
|
|
|
1305
1414
|
return { userData: usersData[userId], consumptionType, freeUsed, purchasedUsed };
|
|
1306
1415
|
}
|
|
1307
1416
|
__name(updateUserData, "updateUserData");
|
|
1308
|
-
async function recordUserUsage(session, commandName, numImages = 1) {
|
|
1417
|
+
async function recordUserUsage(session, commandName, numImages = 1, isSafetyBlock = false) {
|
|
1309
1418
|
const userId = session.userId;
|
|
1310
1419
|
const userName = session.username || session.userId || "未知用户";
|
|
1311
1420
|
if (!userId) return;
|
|
1312
|
-
|
|
1313
|
-
const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages);
|
|
1421
|
+
const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages, isSafetyBlock);
|
|
1314
1422
|
if (isAdmin(userId)) {
|
|
1423
|
+
const blockInfo = isSafetyBlock ? "\n⚠️ 本次请求被安全策略拦截,已扣除使用次数" : "";
|
|
1315
1424
|
await session.send(`📊 使用统计 [管理员]
|
|
1316
1425
|
用户:${userData.userName}
|
|
1317
1426
|
总调用次数:${userData.totalUsageCount}次
|
|
1318
|
-
|
|
1427
|
+
状态:无限制使用${blockInfo}`);
|
|
1319
1428
|
} else {
|
|
1320
1429
|
const remainingToday = Math.max(0, config.dailyFreeLimit - userData.dailyUsageCount);
|
|
1321
1430
|
let consumptionText = "";
|
|
@@ -1326,13 +1435,14 @@ function apply(ctx, config) {
|
|
|
1326
1435
|
} else {
|
|
1327
1436
|
consumptionText = `充值次数 -${purchasedUsed}`;
|
|
1328
1437
|
}
|
|
1438
|
+
const blockInfo = isSafetyBlock ? "\n⚠️ 本次请求被安全策略拦截,已扣除使用次数。请检查内容是否符合使用规范。" : "";
|
|
1329
1439
|
await session.send(`📊 使用统计
|
|
1330
1440
|
用户:${userData.userName}
|
|
1331
1441
|
本次生成:${numImages}张图片
|
|
1332
1442
|
本次消费:${consumptionText}
|
|
1333
1443
|
总调用次数:${userData.totalUsageCount}次
|
|
1334
1444
|
今日剩余免费:${remainingToday}次
|
|
1335
|
-
充值剩余:${userData.remainingPurchasedCount}
|
|
1445
|
+
充值剩余:${userData.remainingPurchasedCount}次${blockInfo}`);
|
|
1336
1446
|
}
|
|
1337
1447
|
logger.info("用户调用记录", {
|
|
1338
1448
|
userId,
|
|
@@ -1345,6 +1455,8 @@ function apply(ctx, config) {
|
|
|
1345
1455
|
totalUsageCount: userData.totalUsageCount,
|
|
1346
1456
|
dailyUsageCount: userData.dailyUsageCount,
|
|
1347
1457
|
remainingPurchasedCount: userData.remainingPurchasedCount,
|
|
1458
|
+
isSafetyBlock,
|
|
1459
|
+
safetyBlockCount: userData.safetyBlockCount,
|
|
1348
1460
|
isAdmin: isAdmin(userId)
|
|
1349
1461
|
});
|
|
1350
1462
|
}
|
|
@@ -1455,8 +1567,10 @@ function apply(ctx, config) {
|
|
|
1455
1567
|
]).catch((error) => {
|
|
1456
1568
|
const userId = session.userId;
|
|
1457
1569
|
if (userId) activeTasks.delete(userId);
|
|
1458
|
-
|
|
1459
|
-
|
|
1570
|
+
const sanitizedError = sanitizeError(error);
|
|
1571
|
+
logger.error("图像处理超时或失败", { userId, error: sanitizedError });
|
|
1572
|
+
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
1573
|
+
return error.message === "命令执行超时" ? "图像处理超时,请重试" : `图像处理失败:${safeMessage}`;
|
|
1460
1574
|
});
|
|
1461
1575
|
}
|
|
1462
1576
|
__name(processImageWithTimeout, "processImageWithTimeout");
|
|
@@ -1541,9 +1655,23 @@ ${infoParts.join("\n")}`;
|
|
|
1541
1655
|
activeTasks.delete(userId);
|
|
1542
1656
|
} catch (error) {
|
|
1543
1657
|
activeTasks.delete(userId);
|
|
1544
|
-
|
|
1658
|
+
const sanitizedError = sanitizeError(error);
|
|
1659
|
+
logger.error("图像处理失败", { userId, error: sanitizedError });
|
|
1660
|
+
const isSafetyBlock = isSafetyBlockError(error);
|
|
1661
|
+
if (isSafetyBlock) {
|
|
1662
|
+
try {
|
|
1663
|
+
await recordUserUsage(session, styleName, imageCount, true);
|
|
1664
|
+
const blockLimitCheck = await checkSafetyBlockLimit(userId);
|
|
1665
|
+
if (!blockLimitCheck.allowed) {
|
|
1666
|
+
return `图像处理失败:内容被安全策略拦截。${blockLimitCheck.message}`;
|
|
1667
|
+
}
|
|
1668
|
+
} catch (recordError) {
|
|
1669
|
+
logger.error("记录安全拦截使用次数失败", { userId, error: recordError });
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1545
1672
|
if (error?.message) {
|
|
1546
|
-
|
|
1673
|
+
const safeMessage = sanitizeString(error.message);
|
|
1674
|
+
return `图像处理失败:${safeMessage}`;
|
|
1547
1675
|
}
|
|
1548
1676
|
return "图像处理失败,请稍后重试";
|
|
1549
1677
|
}
|
|
@@ -1705,9 +1833,23 @@ Prompt: ${prompt}`);
|
|
|
1705
1833
|
activeTasks.delete(userId);
|
|
1706
1834
|
} catch (error) {
|
|
1707
1835
|
activeTasks.delete(userId);
|
|
1708
|
-
|
|
1836
|
+
const sanitizedError = sanitizeError(error);
|
|
1837
|
+
logger.error("图片合成失败", { userId, error: sanitizedError });
|
|
1838
|
+
const isSafetyBlock = isSafetyBlockError(error);
|
|
1839
|
+
if (isSafetyBlock) {
|
|
1840
|
+
try {
|
|
1841
|
+
await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, imageCount, true);
|
|
1842
|
+
const blockLimitCheck = await checkSafetyBlockLimit(userId);
|
|
1843
|
+
if (!blockLimitCheck.allowed) {
|
|
1844
|
+
return `图片合成失败:内容被安全策略拦截。${blockLimitCheck.message}`;
|
|
1845
|
+
}
|
|
1846
|
+
} catch (recordError) {
|
|
1847
|
+
logger.error("记录安全拦截使用次数失败", { userId, error: recordError });
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1709
1850
|
if (error?.message) {
|
|
1710
|
-
|
|
1851
|
+
const safeMessage = sanitizeString(error.message);
|
|
1852
|
+
return `图片合成失败:${safeMessage}`;
|
|
1711
1853
|
}
|
|
1712
1854
|
return "图片合成失败,请稍后重试";
|
|
1713
1855
|
}
|
|
@@ -1718,8 +1860,10 @@ Prompt: ${prompt}`);
|
|
|
1718
1860
|
]).catch((error) => {
|
|
1719
1861
|
const userId = session.userId;
|
|
1720
1862
|
if (userId) activeTasks.delete(userId);
|
|
1721
|
-
|
|
1722
|
-
|
|
1863
|
+
const sanitizedError = sanitizeError(error);
|
|
1864
|
+
logger.error("图片合成超时或失败", { userId, error: sanitizedError });
|
|
1865
|
+
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
1866
|
+
return error.message === "命令执行超时" ? "图片合成超时,请重试" : `图片合成失败:${safeMessage}`;
|
|
1723
1867
|
});
|
|
1724
1868
|
});
|
|
1725
1869
|
ctx.command(`${COMMANDS.RECHARGE} [content:text]`, "为用户充值次数(仅管理员)").action(async ({ session }, content) => {
|
|
@@ -1773,7 +1917,9 @@ Prompt: ${prompt}`);
|
|
|
1773
1917
|
donationCount: 0,
|
|
1774
1918
|
donationAmount: 0,
|
|
1775
1919
|
lastUsed: now,
|
|
1776
|
-
createdAt: now
|
|
1920
|
+
createdAt: now,
|
|
1921
|
+
safetyBlockCount: 0,
|
|
1922
|
+
safetyBlockHistory: []
|
|
1777
1923
|
};
|
|
1778
1924
|
}
|
|
1779
1925
|
const beforeBalance = usersData[userId].remainingPurchasedCount;
|
package/lib/providers/types.d.ts
CHANGED
|
@@ -14,3 +14,11 @@ export interface ProviderConfig {
|
|
|
14
14
|
logger: any;
|
|
15
15
|
ctx: any;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* 清理对象中的敏感信息(API KEY、密钥等)
|
|
19
|
+
*/
|
|
20
|
+
export declare function sanitizeError(error: any): any;
|
|
21
|
+
/**
|
|
22
|
+
* 清理字符串中的 API KEY 模式
|
|
23
|
+
*/
|
|
24
|
+
export declare function sanitizeString(str: string): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-aka-ai-generator",
|
|
3
3
|
"description": "自用AI生成插件(GPTGod & Yunwu)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -9,11 +9,19 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc --watch"
|
|
15
|
+
},
|
|
12
16
|
"keywords": [
|
|
13
17
|
"chatbot",
|
|
14
18
|
"koishi",
|
|
15
19
|
"plugin"
|
|
16
20
|
],
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^20.0.0",
|
|
23
|
+
"typescript": "^5.0.0"
|
|
24
|
+
},
|
|
17
25
|
"peerDependencies": {
|
|
18
26
|
"koishi": "^4.18.9"
|
|
19
27
|
}
|