koishi-plugin-aka-ai-generator 0.8.8 → 0.8.9

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
@@ -33,6 +33,7 @@ export interface Config {
33
33
  commandTimeout: number;
34
34
  defaultNumImages: number;
35
35
  dailyFreeLimit: number;
36
+ unlimitedPlatforms: string[];
36
37
  rateLimitWindow: number;
37
38
  rateLimitMax: number;
38
39
  adminUsers: string[];
package/lib/index.js CHANGED
@@ -1636,6 +1636,39 @@ var UserManager = class {
1636
1636
  return { allowed: true, reservationId };
1637
1637
  });
1638
1638
  }
1639
+ // 只记录调用次数,不扣减配额(用于管理员和平台免配额用户)
1640
+ async recordUsageOnly(userId, userName, commandName, numImages) {
1641
+ await this.loadUsersData();
1642
+ return await this.dataLock.acquire(async () => {
1643
+ if (!this.usersCache) {
1644
+ this.logger.error("recordUsageOnly: usersCache 为空,这不应该发生");
1645
+ this.usersCache = {};
1646
+ }
1647
+ let userData = this.usersCache[userId];
1648
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1649
+ if (!userData) {
1650
+ userData = {
1651
+ userId,
1652
+ userName: userName || userId,
1653
+ totalUsageCount: 0,
1654
+ dailyUsageCount: 0,
1655
+ lastDailyReset: now,
1656
+ purchasedCount: 0,
1657
+ remainingPurchasedCount: 0,
1658
+ donationCount: 0,
1659
+ donationAmount: 0,
1660
+ lastUsed: now,
1661
+ createdAt: now
1662
+ };
1663
+ this.usersCache[userId] = userData;
1664
+ }
1665
+ userData.totalUsageCount += numImages;
1666
+ userData.lastUsed = now;
1667
+ await this.saveUsersDataInternal();
1668
+ this.logger.debug("recordUsageOnly: 仅记录调用次数", { userId, userName, commandName, numImages, totalUsageCount: userData.totalUsageCount });
1669
+ return userData;
1670
+ });
1671
+ }
1639
1672
  // 扣减额度并记录使用
1640
1673
  async consumeQuota(userId, userName, commandName, numImages, config) {
1641
1674
  await this.loadUsersData();
@@ -1898,6 +1931,7 @@ var Config = import_koishi2.Schema.intersect([
1898
1931
  // ===== 6. 限流与配额 =====
1899
1932
  import_koishi2.Schema.object({
1900
1933
  dailyFreeLimit: import_koishi2.Schema.number().default(5).min(1).max(100).description("每日免费调用次数"),
1934
+ unlimitedPlatforms: import_koishi2.Schema.array(import_koishi2.Schema.string()).default(["lark"]).description("不受配额限制的平台列表(如 lark, onebot, discord 等)"),
1901
1935
  rateLimitWindow: import_koishi2.Schema.number().default(300).min(60).max(3600).description("限流时间窗口(秒)"),
1902
1936
  rateLimitMax: import_koishi2.Schema.number().default(3).min(1).max(20).description("限流窗口内最大调用次数")
1903
1937
  }).description("🚦 限流与配额"),
@@ -2090,11 +2124,19 @@ function apply(ctx, config) {
2090
2124
  return input || null;
2091
2125
  }
2092
2126
  __name(getPromptInput, "getPromptInput");
2093
- function buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config2) {
2094
- if (userManager.isAdmin(userData.userId, config2)) {
2127
+ function buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config2, platform) {
2128
+ const isAdmin = userManager.isAdmin(userData.userId, config2);
2129
+ const isPlatformExempt = platform && config2.unlimitedPlatforms?.includes(platform);
2130
+ if (isAdmin) {
2095
2131
  return `📊 使用统计 [管理员]
2096
2132
  用户:${userData.userName}
2097
2133
  总调用次数:${userData.totalUsageCount}次
2134
+ 状态:无限制使用`;
2135
+ }
2136
+ if (isPlatformExempt) {
2137
+ return `📊 使用统计
2138
+ 用户:${userData.userName}
2139
+ 总调用次数:${userData.totalUsageCount}次
2098
2140
  状态:无限制使用`;
2099
2141
  }
2100
2142
  const remainingToday = Math.max(0, config2.dailyFreeLimit - userData.dailyUsageCount);
@@ -2118,8 +2160,23 @@ function apply(ctx, config) {
2118
2160
  async function recordUserUsage(session, commandName, numImages = 1, sendStatsImmediately = true) {
2119
2161
  const userId = session.userId;
2120
2162
  const userName = session.username || session.userId || "未知用户";
2163
+ const platform = session.platform;
2121
2164
  if (!userId) return;
2122
- const { userData, consumptionType, freeUsed, purchasedUsed } = await userManager.consumeQuota(userId, userName, commandName, numImages, config);
2165
+ const isPlatformExempt = platform && config.unlimitedPlatforms?.includes(platform);
2166
+ const isAdmin = userManager.isAdmin(userId, config);
2167
+ let userData;
2168
+ let consumptionType = "free";
2169
+ let freeUsed = 0;
2170
+ let purchasedUsed = 0;
2171
+ if (isAdmin || isPlatformExempt) {
2172
+ userData = await userManager.recordUsageOnly(userId, userName, commandName, numImages);
2173
+ } else {
2174
+ const result = await userManager.consumeQuota(userId, userName, commandName, numImages, config);
2175
+ userData = result.userData;
2176
+ consumptionType = result.consumptionType;
2177
+ freeUsed = result.freeUsed;
2178
+ purchasedUsed = result.purchasedUsed;
2179
+ }
2123
2180
  logger.info("用户调用记录", {
2124
2181
  userId,
2125
2182
  userName: userData.userName,
@@ -2131,11 +2188,13 @@ function apply(ctx, config) {
2131
2188
  totalUsageCount: userData.totalUsageCount,
2132
2189
  dailyUsageCount: userData.dailyUsageCount,
2133
2190
  remainingPurchasedCount: userData.remainingPurchasedCount,
2134
- isAdmin: userManager.isAdmin(userId, config)
2191
+ isAdmin,
2192
+ isPlatformExempt,
2193
+ platform
2135
2194
  });
2136
2195
  if (sendStatsImmediately) {
2137
2196
  try {
2138
- const statsMessage = buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config);
2197
+ const statsMessage = buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config, platform);
2139
2198
  await session.send(statsMessage);
2140
2199
  } catch (error) {
2141
2200
  logger.warn("发送统计信息失败", { userId, error: sanitizeError(error) });
@@ -2143,7 +2202,7 @@ function apply(ctx, config) {
2143
2202
  } else {
2144
2203
  setImmediate(async () => {
2145
2204
  try {
2146
- const statsMessage = buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config);
2205
+ const statsMessage = buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config, platform);
2147
2206
  await session.send(statsMessage);
2148
2207
  logger.debug("统计信息已异步发送", { userId, commandName });
2149
2208
  } catch (error) {
@@ -130,6 +130,7 @@ export declare class UserManager {
130
130
  message?: string;
131
131
  reservationId?: string;
132
132
  }>;
133
+ recordUsageOnly(userId: string, userName: string, commandName: string, numImages: number): Promise<UserData>;
133
134
  consumeQuota(userId: string, userName: string, commandName: string, numImages: number, config: Config): Promise<{
134
135
  userData: UserData;
135
136
  consumptionType: 'free' | 'purchased' | 'mixed';
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.8.8",
4
+ "version": "0.8.9",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [