koishi-plugin-aka-ai-generator 0.4.4 → 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 CHANGED
@@ -25,6 +25,8 @@ export interface UserData {
25
25
  donationAmount: number;
26
26
  lastUsed: string;
27
27
  createdAt: string;
28
+ safetyBlockCount: number;
29
+ safetyBlockHistory: string[];
28
30
  }
29
31
  export interface UsersData {
30
32
  [userId: string]: UserData;
package/lib/index.js CHANGED
@@ -1207,6 +1207,46 @@ function apply(ctx, config) {
1207
1207
  return { allowed: true, isAdmin: false };
1208
1208
  }
1209
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");
1210
1250
  async function getPromptInput(session, message) {
1211
1251
  await session.send(message);
1212
1252
  const input = await session.prompt(3e4);
@@ -1286,15 +1326,24 @@ function apply(ctx, config) {
1286
1326
  donationCount: 0,
1287
1327
  donationAmount: 0,
1288
1328
  lastUsed: (/* @__PURE__ */ new Date()).toISOString(),
1289
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1329
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1330
+ safetyBlockCount: 0,
1331
+ safetyBlockHistory: []
1290
1332
  };
1291
1333
  await saveUsersData(usersData);
1292
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
+ }
1293
1342
  }
1294
1343
  return usersData[userId];
1295
1344
  }
1296
1345
  __name(getUserData, "getUserData");
1297
- async function updateUserData(userId, userName, commandName, numImages = 1) {
1346
+ async function updateUserData(userId, userName, commandName, numImages = 1, isSafetyBlock = false) {
1298
1347
  const usersData = await loadUsersData();
1299
1348
  const now = (/* @__PURE__ */ new Date()).toISOString();
1300
1349
  const today = (/* @__PURE__ */ new Date()).toDateString();
@@ -1310,11 +1359,19 @@ function apply(ctx, config) {
1310
1359
  donationCount: 0,
1311
1360
  donationAmount: 0,
1312
1361
  lastUsed: now,
1313
- createdAt: now
1362
+ createdAt: now,
1363
+ safetyBlockCount: isSafetyBlock ? numImages : 0,
1364
+ safetyBlockHistory: isSafetyBlock ? [now] : []
1314
1365
  };
1315
1366
  await saveUsersData(usersData);
1316
1367
  return { userData: usersData[userId], consumptionType: "free", freeUsed: numImages, purchasedUsed: 0 };
1317
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
+ }
1318
1375
  usersData[userId].totalUsageCount += numImages;
1319
1376
  usersData[userId].lastUsed = now;
1320
1377
  const lastReset = new Date(usersData[userId].lastDailyReset || usersData[userId].createdAt).toDateString();
@@ -1338,6 +1395,13 @@ function apply(ctx, config) {
1338
1395
  purchasedUsed = purchasedToUse;
1339
1396
  remainingToConsume -= purchasedToUse;
1340
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
+ }
1341
1405
  await saveUsersData(usersData);
1342
1406
  let consumptionType;
1343
1407
  if (freeUsed > 0 && purchasedUsed > 0) {
@@ -1350,16 +1414,17 @@ function apply(ctx, config) {
1350
1414
  return { userData: usersData[userId], consumptionType, freeUsed, purchasedUsed };
1351
1415
  }
1352
1416
  __name(updateUserData, "updateUserData");
1353
- async function recordUserUsage(session, commandName, numImages = 1) {
1417
+ async function recordUserUsage(session, commandName, numImages = 1, isSafetyBlock = false) {
1354
1418
  const userId = session.userId;
1355
1419
  const userName = session.username || session.userId || "未知用户";
1356
1420
  if (!userId) return;
1357
- const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages);
1421
+ const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages, isSafetyBlock);
1358
1422
  if (isAdmin(userId)) {
1423
+ const blockInfo = isSafetyBlock ? "\n⚠️ 本次请求被安全策略拦截,已扣除使用次数" : "";
1359
1424
  await session.send(`📊 使用统计 [管理员]
1360
1425
  用户:${userData.userName}
1361
1426
  总调用次数:${userData.totalUsageCount}次
1362
- 状态:无限制使用`);
1427
+ 状态:无限制使用${blockInfo}`);
1363
1428
  } else {
1364
1429
  const remainingToday = Math.max(0, config.dailyFreeLimit - userData.dailyUsageCount);
1365
1430
  let consumptionText = "";
@@ -1370,13 +1435,14 @@ function apply(ctx, config) {
1370
1435
  } else {
1371
1436
  consumptionText = `充值次数 -${purchasedUsed}`;
1372
1437
  }
1438
+ const blockInfo = isSafetyBlock ? "\n⚠️ 本次请求被安全策略拦截,已扣除使用次数。请检查内容是否符合使用规范。" : "";
1373
1439
  await session.send(`📊 使用统计
1374
1440
  用户:${userData.userName}
1375
1441
  本次生成:${numImages}张图片
1376
1442
  本次消费:${consumptionText}
1377
1443
  总调用次数:${userData.totalUsageCount}次
1378
1444
  今日剩余免费:${remainingToday}次
1379
- 充值剩余:${userData.remainingPurchasedCount}次`);
1445
+ 充值剩余:${userData.remainingPurchasedCount}次${blockInfo}`);
1380
1446
  }
1381
1447
  logger.info("用户调用记录", {
1382
1448
  userId,
@@ -1389,6 +1455,8 @@ function apply(ctx, config) {
1389
1455
  totalUsageCount: userData.totalUsageCount,
1390
1456
  dailyUsageCount: userData.dailyUsageCount,
1391
1457
  remainingPurchasedCount: userData.remainingPurchasedCount,
1458
+ isSafetyBlock,
1459
+ safetyBlockCount: userData.safetyBlockCount,
1392
1460
  isAdmin: isAdmin(userId)
1393
1461
  });
1394
1462
  }
@@ -1589,6 +1657,18 @@ ${infoParts.join("\n")}`;
1589
1657
  activeTasks.delete(userId);
1590
1658
  const sanitizedError = sanitizeError(error);
1591
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
+ }
1592
1672
  if (error?.message) {
1593
1673
  const safeMessage = sanitizeString(error.message);
1594
1674
  return `图像处理失败:${safeMessage}`;
@@ -1755,6 +1835,18 @@ Prompt: ${prompt}`);
1755
1835
  activeTasks.delete(userId);
1756
1836
  const sanitizedError = sanitizeError(error);
1757
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
+ }
1758
1850
  if (error?.message) {
1759
1851
  const safeMessage = sanitizeString(error.message);
1760
1852
  return `图片合成失败:${safeMessage}`;
@@ -1825,7 +1917,9 @@ Prompt: ${prompt}`);
1825
1917
  donationCount: 0,
1826
1918
  donationAmount: 0,
1827
1919
  lastUsed: now,
1828
- createdAt: now
1920
+ createdAt: now,
1921
+ safetyBlockCount: 0,
1922
+ safetyBlockHistory: []
1829
1923
  };
1830
1924
  }
1831
1925
  const beforeBalance = usersData[userId].remainingPurchasedCount;
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.4",
4
+ "version": "0.5.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [