koishi-plugin-aka-ai-generator 0.2.12 → 0.2.14
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 +99 -48
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -599,7 +599,8 @@ var COMMANDS = {
|
|
|
599
599
|
QUERY_QUOTA: "图像额度",
|
|
600
600
|
RECHARGE: "图像充值",
|
|
601
601
|
RECHARGE_HISTORY: "图像充值记录",
|
|
602
|
-
FUNCTION_LIST: "图像功能"
|
|
602
|
+
FUNCTION_LIST: "图像功能",
|
|
603
|
+
IMAGE_COMMANDS: "图像指令"
|
|
603
604
|
};
|
|
604
605
|
var StyleItemSchema = import_koishi.Schema.object({
|
|
605
606
|
commandName: import_koishi.Schema.string().required().description("命令名称(不含前缀斜杠)"),
|
|
@@ -883,7 +884,7 @@ function apply(ctx, config) {
|
|
|
883
884
|
rateLimitMap.set(userId, userTimestamps);
|
|
884
885
|
}
|
|
885
886
|
__name(updateRateLimit, "updateRateLimit");
|
|
886
|
-
async function checkDailyLimit(userId) {
|
|
887
|
+
async function checkDailyLimit(userId, numImages = 1) {
|
|
887
888
|
if (isAdmin(userId)) {
|
|
888
889
|
return { allowed: true, isAdmin: true };
|
|
889
890
|
}
|
|
@@ -894,25 +895,33 @@ function apply(ctx, config) {
|
|
|
894
895
|
const usersData = await loadUsersData();
|
|
895
896
|
const userData = usersData[userId];
|
|
896
897
|
if (!userData) {
|
|
898
|
+
if (numImages > config.dailyFreeLimit) {
|
|
899
|
+
return {
|
|
900
|
+
allowed: false,
|
|
901
|
+
message: `生成 ${numImages} 张图片需要 ${numImages} 次可用次数,但您的可用次数不足(今日免费:${config.dailyFreeLimit}次,充值:0次)`,
|
|
902
|
+
isAdmin: false
|
|
903
|
+
};
|
|
904
|
+
}
|
|
897
905
|
return { allowed: true, isAdmin: false };
|
|
898
906
|
}
|
|
899
907
|
const today = (/* @__PURE__ */ new Date()).toDateString();
|
|
900
908
|
const lastReset = new Date(userData.lastDailyReset || userData.createdAt).toDateString();
|
|
909
|
+
let dailyCount = userData.dailyUsageCount;
|
|
901
910
|
if (today !== lastReset) {
|
|
911
|
+
dailyCount = 0;
|
|
902
912
|
userData.dailyUsageCount = 0;
|
|
903
913
|
userData.lastDailyReset = (/* @__PURE__ */ new Date()).toISOString();
|
|
904
914
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
915
|
+
const remainingToday = Math.max(0, config.dailyFreeLimit - dailyCount);
|
|
916
|
+
const totalAvailable = remainingToday + userData.remainingPurchasedCount;
|
|
917
|
+
if (totalAvailable < numImages) {
|
|
918
|
+
return {
|
|
919
|
+
allowed: false,
|
|
920
|
+
message: `生成 ${numImages} 张图片需要 ${numImages} 次可用次数,但您的可用次数不足(今日免费剩余:${remainingToday}次,充值剩余:${userData.remainingPurchasedCount}次,共${totalAvailable}次)`,
|
|
921
|
+
isAdmin: false
|
|
922
|
+
};
|
|
910
923
|
}
|
|
911
|
-
return {
|
|
912
|
-
allowed: false,
|
|
913
|
-
message: `今日免费次数已用完(${config.dailyFreeLimit}次),充值次数也已用完。请联系管理员充值或明天再试`,
|
|
914
|
-
isAdmin: false
|
|
915
|
-
};
|
|
924
|
+
return { allowed: true, isAdmin: false };
|
|
916
925
|
}
|
|
917
926
|
__name(checkDailyLimit, "checkDailyLimit");
|
|
918
927
|
async function getPromptInput(session, message) {
|
|
@@ -1002,7 +1011,7 @@ function apply(ctx, config) {
|
|
|
1002
1011
|
return usersData[userId];
|
|
1003
1012
|
}
|
|
1004
1013
|
__name(getUserData, "getUserData");
|
|
1005
|
-
async function updateUserData(userId, userName, commandName) {
|
|
1014
|
+
async function updateUserData(userId, userName, commandName, numImages = 1) {
|
|
1006
1015
|
const usersData = await loadUsersData();
|
|
1007
1016
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1008
1017
|
const today = (/* @__PURE__ */ new Date()).toDateString();
|
|
@@ -1010,8 +1019,8 @@ function apply(ctx, config) {
|
|
|
1010
1019
|
usersData[userId] = {
|
|
1011
1020
|
userId,
|
|
1012
1021
|
userName: userId,
|
|
1013
|
-
totalUsageCount:
|
|
1014
|
-
dailyUsageCount:
|
|
1022
|
+
totalUsageCount: numImages,
|
|
1023
|
+
dailyUsageCount: numImages,
|
|
1015
1024
|
lastDailyReset: now,
|
|
1016
1025
|
purchasedCount: 0,
|
|
1017
1026
|
remainingPurchasedCount: 0,
|
|
@@ -1021,35 +1030,49 @@ function apply(ctx, config) {
|
|
|
1021
1030
|
createdAt: now
|
|
1022
1031
|
};
|
|
1023
1032
|
await saveUsersData(usersData);
|
|
1024
|
-
return { userData: usersData[userId], consumptionType: "free" };
|
|
1033
|
+
return { userData: usersData[userId], consumptionType: "free", freeUsed: numImages, purchasedUsed: 0 };
|
|
1025
1034
|
}
|
|
1026
|
-
usersData[userId].totalUsageCount +=
|
|
1035
|
+
usersData[userId].totalUsageCount += numImages;
|
|
1027
1036
|
usersData[userId].lastUsed = now;
|
|
1028
1037
|
const lastReset = new Date(usersData[userId].lastDailyReset || usersData[userId].createdAt).toDateString();
|
|
1029
1038
|
if (today !== lastReset) {
|
|
1030
1039
|
usersData[userId].dailyUsageCount = 0;
|
|
1031
1040
|
usersData[userId].lastDailyReset = now;
|
|
1032
1041
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
usersData[userId].
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
+
let remainingToConsume = numImages;
|
|
1043
|
+
let freeUsed = 0;
|
|
1044
|
+
let purchasedUsed = 0;
|
|
1045
|
+
const availableFree = Math.max(0, config.dailyFreeLimit - usersData[userId].dailyUsageCount);
|
|
1046
|
+
if (availableFree > 0) {
|
|
1047
|
+
const freeToUse = Math.min(availableFree, remainingToConsume);
|
|
1048
|
+
usersData[userId].dailyUsageCount += freeToUse;
|
|
1049
|
+
freeUsed = freeToUse;
|
|
1050
|
+
remainingToConsume -= freeToUse;
|
|
1051
|
+
}
|
|
1052
|
+
if (remainingToConsume > 0) {
|
|
1053
|
+
const purchasedToUse = Math.min(usersData[userId].remainingPurchasedCount, remainingToConsume);
|
|
1054
|
+
usersData[userId].remainingPurchasedCount -= purchasedToUse;
|
|
1055
|
+
purchasedUsed = purchasedToUse;
|
|
1056
|
+
remainingToConsume -= purchasedToUse;
|
|
1042
1057
|
}
|
|
1043
1058
|
await saveUsersData(usersData);
|
|
1044
|
-
|
|
1059
|
+
let consumptionType;
|
|
1060
|
+
if (freeUsed > 0 && purchasedUsed > 0) {
|
|
1061
|
+
consumptionType = "mixed";
|
|
1062
|
+
} else if (freeUsed > 0) {
|
|
1063
|
+
consumptionType = "free";
|
|
1064
|
+
} else {
|
|
1065
|
+
consumptionType = "purchased";
|
|
1066
|
+
}
|
|
1067
|
+
return { userData: usersData[userId], consumptionType, freeUsed, purchasedUsed };
|
|
1045
1068
|
}
|
|
1046
1069
|
__name(updateUserData, "updateUserData");
|
|
1047
|
-
async function recordUserUsage(session, commandName) {
|
|
1070
|
+
async function recordUserUsage(session, commandName, numImages = 1) {
|
|
1048
1071
|
const userId = session.userId;
|
|
1049
1072
|
const userName = session.username || session.userId || "未知用户";
|
|
1050
1073
|
if (!userId) return;
|
|
1051
1074
|
updateRateLimit(userId);
|
|
1052
|
-
const { userData, consumptionType } = await updateUserData(userId, userName, commandName);
|
|
1075
|
+
const { userData, consumptionType, freeUsed, purchasedUsed } = await updateUserData(userId, userName, commandName, numImages);
|
|
1053
1076
|
if (isAdmin(userId)) {
|
|
1054
1077
|
await session.send(`📊 使用统计 [管理员]
|
|
1055
1078
|
用户:${userData.userName}
|
|
@@ -1057,10 +1080,18 @@ function apply(ctx, config) {
|
|
|
1057
1080
|
状态:无限制使用`);
|
|
1058
1081
|
} else {
|
|
1059
1082
|
const remainingToday = Math.max(0, config.dailyFreeLimit - userData.dailyUsageCount);
|
|
1060
|
-
|
|
1083
|
+
let consumptionText = "";
|
|
1084
|
+
if (consumptionType === "mixed") {
|
|
1085
|
+
consumptionText = `每日免费次数 -${freeUsed},充值次数 -${purchasedUsed}`;
|
|
1086
|
+
} else if (consumptionType === "free") {
|
|
1087
|
+
consumptionText = `每日免费次数 -${freeUsed}`;
|
|
1088
|
+
} else {
|
|
1089
|
+
consumptionText = `充值次数 -${purchasedUsed}`;
|
|
1090
|
+
}
|
|
1061
1091
|
await session.send(`📊 使用统计
|
|
1062
1092
|
用户:${userData.userName}
|
|
1063
|
-
|
|
1093
|
+
本次生成:${numImages}张图片
|
|
1094
|
+
本次消费:${consumptionText}
|
|
1064
1095
|
总调用次数:${userData.totalUsageCount}次
|
|
1065
1096
|
今日剩余免费:${remainingToday}次
|
|
1066
1097
|
充值剩余:${userData.remainingPurchasedCount}次`);
|
|
@@ -1069,10 +1100,13 @@ function apply(ctx, config) {
|
|
|
1069
1100
|
userId,
|
|
1070
1101
|
userName: userData.userName,
|
|
1071
1102
|
commandName,
|
|
1103
|
+
numImages,
|
|
1104
|
+
consumptionType,
|
|
1105
|
+
freeUsed,
|
|
1106
|
+
purchasedUsed,
|
|
1072
1107
|
totalUsageCount: userData.totalUsageCount,
|
|
1073
1108
|
dailyUsageCount: userData.dailyUsageCount,
|
|
1074
1109
|
remainingPurchasedCount: userData.remainingPurchasedCount,
|
|
1075
|
-
consumptionType,
|
|
1076
1110
|
isAdmin: isAdmin(userId)
|
|
1077
1111
|
});
|
|
1078
1112
|
}
|
|
@@ -1207,7 +1241,7 @@ ${infoParts.join("\n")}`;
|
|
|
1207
1241
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1208
1242
|
}
|
|
1209
1243
|
}
|
|
1210
|
-
await recordUserUsage(session, styleName);
|
|
1244
|
+
await recordUserUsage(session, styleName, images.length);
|
|
1211
1245
|
activeTasks.delete(userId);
|
|
1212
1246
|
} catch (error) {
|
|
1213
1247
|
activeTasks.delete(userId);
|
|
@@ -1225,10 +1259,6 @@ ${infoParts.join("\n")}`;
|
|
|
1225
1259
|
ctx.command(`${style.commandName} [img:text]`, "图像风格转换").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async (argv, img) => {
|
|
1226
1260
|
const { session, options } = argv;
|
|
1227
1261
|
if (!session?.userId) return "会话无效";
|
|
1228
|
-
const limitCheck = await checkDailyLimit(session.userId);
|
|
1229
|
-
if (!limitCheck.allowed) {
|
|
1230
|
-
return limitCheck.message;
|
|
1231
|
-
}
|
|
1232
1262
|
const modifiers = parseStyleCommandModifiers(argv, img);
|
|
1233
1263
|
let userPromptParts = [];
|
|
1234
1264
|
if (modifiers.customAdditions?.length) {
|
|
@@ -1250,13 +1280,18 @@ ${infoParts.join("\n")}`;
|
|
|
1250
1280
|
}
|
|
1251
1281
|
}
|
|
1252
1282
|
}
|
|
1283
|
+
const numImages = options?.num || promptNumImages || config.defaultNumImages;
|
|
1284
|
+
const limitCheck = await checkDailyLimit(session.userId, numImages);
|
|
1285
|
+
if (!limitCheck.allowed) {
|
|
1286
|
+
return limitCheck.message;
|
|
1287
|
+
}
|
|
1253
1288
|
const promptSegments = [style.prompt];
|
|
1254
1289
|
if (cleanedUserPrompt) {
|
|
1255
1290
|
promptSegments.push(cleanedUserPrompt);
|
|
1256
1291
|
}
|
|
1257
1292
|
const mergedPrompt = promptSegments.filter(Boolean).join(" - ");
|
|
1258
1293
|
const requestContext = {
|
|
1259
|
-
numImages
|
|
1294
|
+
numImages
|
|
1260
1295
|
};
|
|
1261
1296
|
if (modifiers.modelMapping?.provider) {
|
|
1262
1297
|
requestContext.provider = modifiers.modelMapping.provider;
|
|
@@ -1280,10 +1315,6 @@ ${infoParts.join("\n")}`;
|
|
|
1280
1315
|
}
|
|
1281
1316
|
ctx.command(COMMANDS.GENERATE_IMAGE, "使用自定义prompt进行图像处理").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async ({ session, options }) => {
|
|
1282
1317
|
if (!session?.userId) return "会话无效";
|
|
1283
|
-
const limitCheck = await checkDailyLimit(session.userId);
|
|
1284
|
-
if (!limitCheck.allowed) {
|
|
1285
|
-
return limitCheck.message;
|
|
1286
|
-
}
|
|
1287
1318
|
return Promise.race([
|
|
1288
1319
|
(async () => {
|
|
1289
1320
|
const userId = session.userId;
|
|
@@ -1350,6 +1381,10 @@ ${infoParts.join("\n")}`;
|
|
|
1350
1381
|
if (imageCount < 1 || imageCount > 4) {
|
|
1351
1382
|
return "生成数量必须在 1-4 之间";
|
|
1352
1383
|
}
|
|
1384
|
+
const limitCheck = await checkDailyLimit(userId, imageCount);
|
|
1385
|
+
if (!limitCheck.allowed) {
|
|
1386
|
+
return limitCheck.message;
|
|
1387
|
+
}
|
|
1353
1388
|
logger.info("开始自定义图像处理", {
|
|
1354
1389
|
userId,
|
|
1355
1390
|
imageUrl,
|
|
@@ -1372,7 +1407,7 @@ Prompt: ${prompt}`);
|
|
|
1372
1407
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1373
1408
|
}
|
|
1374
1409
|
}
|
|
1375
|
-
await recordUserUsage(session, COMMANDS.GENERATE_IMAGE);
|
|
1410
|
+
await recordUserUsage(session, COMMANDS.GENERATE_IMAGE, resultImages.length);
|
|
1376
1411
|
activeTasks.delete(userId);
|
|
1377
1412
|
} catch (error) {
|
|
1378
1413
|
activeTasks.delete(userId);
|
|
@@ -1395,10 +1430,6 @@ Prompt: ${prompt}`);
|
|
|
1395
1430
|
});
|
|
1396
1431
|
ctx.command(COMMANDS.COMPOSE_IMAGE, "合成多张图片,使用自定义prompt控制合成效果").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async ({ session, options }) => {
|
|
1397
1432
|
if (!session?.userId) return "会话无效";
|
|
1398
|
-
const limitCheck = await checkDailyLimit(session.userId);
|
|
1399
|
-
if (!limitCheck.allowed) {
|
|
1400
|
-
return limitCheck.message;
|
|
1401
|
-
}
|
|
1402
1433
|
return Promise.race([
|
|
1403
1434
|
(async () => {
|
|
1404
1435
|
const userId = session.userId;
|
|
@@ -1455,6 +1486,10 @@ Prompt: ${prompt}`);
|
|
|
1455
1486
|
if (imageCount < 1 || imageCount > 4) {
|
|
1456
1487
|
return "生成数量必须在 1-4 之间";
|
|
1457
1488
|
}
|
|
1489
|
+
const limitCheck = await checkDailyLimit(userId, imageCount);
|
|
1490
|
+
if (!limitCheck.allowed) {
|
|
1491
|
+
return limitCheck.message;
|
|
1492
|
+
}
|
|
1458
1493
|
logger.info("开始图片合成处理", {
|
|
1459
1494
|
userId,
|
|
1460
1495
|
imageUrls: collectedImages,
|
|
@@ -1478,7 +1513,7 @@ Prompt: ${prompt}`);
|
|
|
1478
1513
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1479
1514
|
}
|
|
1480
1515
|
}
|
|
1481
|
-
await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE);
|
|
1516
|
+
await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, resultImages.length);
|
|
1482
1517
|
activeTasks.delete(userId);
|
|
1483
1518
|
} catch (error) {
|
|
1484
1519
|
activeTasks.delete(userId);
|
|
@@ -1705,6 +1740,22 @@ Prompt: ${prompt}`);
|
|
|
1705
1740
|
return "获取功能列表失败,请稍后重试";
|
|
1706
1741
|
}
|
|
1707
1742
|
});
|
|
1743
|
+
ctx.command(COMMANDS.IMAGE_COMMANDS, "查看图像生成指令列表").action(async ({ session }) => {
|
|
1744
|
+
if (!session?.userId) return "会话无效";
|
|
1745
|
+
const globalConfig = ctx.root.config;
|
|
1746
|
+
const prefixConfig = globalConfig.prefix;
|
|
1747
|
+
let prefix = "";
|
|
1748
|
+
if (Array.isArray(prefixConfig) && prefixConfig.length > 0) {
|
|
1749
|
+
prefix = prefixConfig[0];
|
|
1750
|
+
} else if (typeof prefixConfig === "string") {
|
|
1751
|
+
prefix = prefixConfig;
|
|
1752
|
+
}
|
|
1753
|
+
const lines = ["🎨 图像生成指令列表:\n"];
|
|
1754
|
+
commandRegistry.userCommands.forEach((cmd) => {
|
|
1755
|
+
lines.push(`${prefix}${cmd.name} - ${cmd.description}`);
|
|
1756
|
+
});
|
|
1757
|
+
return lines.join("\n");
|
|
1758
|
+
});
|
|
1708
1759
|
const providerLabel = config.provider === "gptgod" ? "GPTGod" : "云雾 Gemini 2.5 Flash Image";
|
|
1709
1760
|
logger.info(`aka-ai-generator 插件已启动 (${providerLabel})`);
|
|
1710
1761
|
}
|