koishi-plugin-aka-ai-generator 0.6.8 → 0.6.10
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 +149 -53
- package/lib/providers/gemini.d.ts +1 -1
- package/lib/providers/gptgod.d.ts +1 -1
- package/lib/providers/types.d.ts +2 -1
- package/lib/services/UserManager.d.ts +5 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -295,7 +295,7 @@ var GptGodProvider = class {
|
|
|
295
295
|
constructor(config) {
|
|
296
296
|
this.config = config;
|
|
297
297
|
}
|
|
298
|
-
async generateImages(prompt, imageUrls, numImages) {
|
|
298
|
+
async generateImages(prompt, imageUrls, numImages, onImageGenerated) {
|
|
299
299
|
const urls = Array.isArray(imageUrls) ? imageUrls : [imageUrls];
|
|
300
300
|
const logger = this.config.logger;
|
|
301
301
|
const ctx = this.config.ctx;
|
|
@@ -410,7 +410,18 @@ var GptGodProvider = class {
|
|
|
410
410
|
throw new Error(`生成失败:${shortError}`);
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
|
-
|
|
413
|
+
for (let imgIdx = 0; imgIdx < images.length; imgIdx++) {
|
|
414
|
+
const imageUrl = images[imgIdx];
|
|
415
|
+
const currentIndex = allImages.length;
|
|
416
|
+
allImages.push(imageUrl);
|
|
417
|
+
if (onImageGenerated) {
|
|
418
|
+
try {
|
|
419
|
+
await onImageGenerated(imageUrl, currentIndex, numImages);
|
|
420
|
+
} catch (callbackError) {
|
|
421
|
+
logger.warn("图片生成回调函数执行失败", { error: sanitizeError(callbackError) });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
414
425
|
logger.success("GPTGod 图像编辑 API 调用成功", { current: i + 1, total: numImages });
|
|
415
426
|
success = true;
|
|
416
427
|
break;
|
|
@@ -609,7 +620,7 @@ var GeminiProvider = class {
|
|
|
609
620
|
constructor(config) {
|
|
610
621
|
this.config = config;
|
|
611
622
|
}
|
|
612
|
-
async generateImages(prompt, imageUrls, numImages) {
|
|
623
|
+
async generateImages(prompt, imageUrls, numImages, onImageGenerated) {
|
|
613
624
|
let urls = [];
|
|
614
625
|
if (Array.isArray(imageUrls)) {
|
|
615
626
|
urls = imageUrls.filter((url) => url && typeof url === "string" && url.trim());
|
|
@@ -682,8 +693,19 @@ var GeminiProvider = class {
|
|
|
682
693
|
});
|
|
683
694
|
} else {
|
|
684
695
|
logger.success("Gemini API 调用成功", { current: i + 1, total: numImages, imagesCount: images.length });
|
|
696
|
+
for (let imgIdx = 0; imgIdx < images.length; imgIdx++) {
|
|
697
|
+
const imageUrl = images[imgIdx];
|
|
698
|
+
const currentIndex = allImages.length;
|
|
699
|
+
allImages.push(imageUrl);
|
|
700
|
+
if (onImageGenerated) {
|
|
701
|
+
try {
|
|
702
|
+
await onImageGenerated(imageUrl, currentIndex, numImages);
|
|
703
|
+
} catch (callbackError) {
|
|
704
|
+
logger.warn("图片生成回调函数执行失败", { error: sanitizeError(callbackError) });
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
685
708
|
}
|
|
686
|
-
allImages.push(...images);
|
|
687
709
|
} catch (error) {
|
|
688
710
|
const sanitizedError = sanitizeError(error);
|
|
689
711
|
const safeMessage = typeof error?.message === "string" ? sanitizeString(error.message) : "未知错误";
|
|
@@ -983,6 +1005,36 @@ var UserManager = class {
|
|
|
983
1005
|
}
|
|
984
1006
|
return { allowed: true, isAdmin: false };
|
|
985
1007
|
}
|
|
1008
|
+
// 原子性地检查并预留额度(防止并发绕过)
|
|
1009
|
+
async checkAndReserveQuota(userId, userName, numImages, config) {
|
|
1010
|
+
if (this.isAdmin(userId, config)) {
|
|
1011
|
+
return { allowed: true, reservationId: "admin" };
|
|
1012
|
+
}
|
|
1013
|
+
const rateLimitCheck = this.checkRateLimit(userId, config);
|
|
1014
|
+
if (!rateLimitCheck.allowed) {
|
|
1015
|
+
return { ...rateLimitCheck };
|
|
1016
|
+
}
|
|
1017
|
+
this.updateRateLimit(userId);
|
|
1018
|
+
return await this.dataLock.acquire(async () => {
|
|
1019
|
+
const userData = await this.getUserData(userId, userName);
|
|
1020
|
+
const today = (/* @__PURE__ */ new Date()).toDateString();
|
|
1021
|
+
const lastReset = new Date(userData.lastDailyReset || userData.createdAt).toDateString();
|
|
1022
|
+
let dailyCount = userData.dailyUsageCount;
|
|
1023
|
+
if (today !== lastReset) {
|
|
1024
|
+
dailyCount = 0;
|
|
1025
|
+
}
|
|
1026
|
+
const remainingToday = Math.max(0, config.dailyFreeLimit - dailyCount);
|
|
1027
|
+
const totalAvailable = remainingToday + userData.remainingPurchasedCount;
|
|
1028
|
+
if (totalAvailable < numImages) {
|
|
1029
|
+
return {
|
|
1030
|
+
allowed: false,
|
|
1031
|
+
message: `生成 ${numImages} 张图片需要 ${numImages} 次可用次数,但您的可用次数不足(今日免费剩余:${remainingToday}次,充值剩余:${userData.remainingPurchasedCount}次,共${totalAvailable}次)`
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
const reservationId = `${userId}_${Date.now()}_${Math.random()}`;
|
|
1035
|
+
return { allowed: true, reservationId };
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
986
1038
|
// 扣减额度并记录使用
|
|
987
1039
|
async consumeQuota(userId, userName, commandName, numImages, config) {
|
|
988
1040
|
return await this.dataLock.acquire(async () => {
|
|
@@ -1059,7 +1111,7 @@ var UserManager = class {
|
|
|
1059
1111
|
if (blockCount >= config.securityBlockWarningThreshold && !hasWarning) {
|
|
1060
1112
|
this.securityWarningMap.set(userId, true);
|
|
1061
1113
|
shouldWarn = true;
|
|
1062
|
-
} else if (
|
|
1114
|
+
} else if (blockCount > config.securityBlockWarningThreshold) {
|
|
1063
1115
|
shouldDeduct = true;
|
|
1064
1116
|
}
|
|
1065
1117
|
return { shouldWarn, shouldDeduct, blockCount };
|
|
@@ -1318,34 +1370,36 @@ function apply(ctx, config) {
|
|
|
1318
1370
|
return input || null;
|
|
1319
1371
|
}
|
|
1320
1372
|
__name(getPromptInput, "getPromptInput");
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
if (!userId) return;
|
|
1325
|
-
const { userData, consumptionType, freeUsed, purchasedUsed } = await userManager.consumeQuota(userId, userName, commandName, numImages, config);
|
|
1326
|
-
if (userManager.isAdmin(userId, config)) {
|
|
1327
|
-
await session.send(`📊 使用统计 [管理员]
|
|
1373
|
+
function buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config2) {
|
|
1374
|
+
if (userManager.isAdmin(userData.userId, config2)) {
|
|
1375
|
+
return `📊 使用统计 [管理员]
|
|
1328
1376
|
用户:${userData.userName}
|
|
1329
1377
|
总调用次数:${userData.totalUsageCount}次
|
|
1330
|
-
|
|
1378
|
+
状态:无限制使用`;
|
|
1379
|
+
}
|
|
1380
|
+
const remainingToday = Math.max(0, config2.dailyFreeLimit - userData.dailyUsageCount);
|
|
1381
|
+
let consumptionText = "";
|
|
1382
|
+
if (consumptionType === "mixed") {
|
|
1383
|
+
consumptionText = `每日免费次数 -${freeUsed},充值次数 -${purchasedUsed}`;
|
|
1384
|
+
} else if (consumptionType === "free") {
|
|
1385
|
+
consumptionText = `每日免费次数 -${freeUsed}`;
|
|
1331
1386
|
} else {
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
consumptionText = `每日免费次数 -${freeUsed},充值次数 -${purchasedUsed}`;
|
|
1336
|
-
} else if (consumptionType === "free") {
|
|
1337
|
-
consumptionText = `每日免费次数 -${freeUsed}`;
|
|
1338
|
-
} else {
|
|
1339
|
-
consumptionText = `充值次数 -${purchasedUsed}`;
|
|
1340
|
-
}
|
|
1341
|
-
await session.send(`📊 使用统计
|
|
1387
|
+
consumptionText = `充值次数 -${purchasedUsed}`;
|
|
1388
|
+
}
|
|
1389
|
+
return `📊 使用统计
|
|
1342
1390
|
用户:${userData.userName}
|
|
1343
1391
|
本次生成:${numImages}张图片
|
|
1344
1392
|
本次消费:${consumptionText}
|
|
1345
1393
|
总调用次数:${userData.totalUsageCount}次
|
|
1346
1394
|
今日剩余免费:${remainingToday}次
|
|
1347
|
-
充值剩余:${userData.remainingPurchasedCount}
|
|
1348
|
-
|
|
1395
|
+
充值剩余:${userData.remainingPurchasedCount}次`;
|
|
1396
|
+
}
|
|
1397
|
+
__name(buildStatsMessage, "buildStatsMessage");
|
|
1398
|
+
async function recordUserUsage(session, commandName, numImages = 1) {
|
|
1399
|
+
const userId = session.userId;
|
|
1400
|
+
const userName = session.username || session.userId || "未知用户";
|
|
1401
|
+
if (!userId) return;
|
|
1402
|
+
const { userData, consumptionType, freeUsed, purchasedUsed } = await userManager.consumeQuota(userId, userName, commandName, numImages, config);
|
|
1349
1403
|
logger.info("用户调用记录", {
|
|
1350
1404
|
userId,
|
|
1351
1405
|
userName: userData.userName,
|
|
@@ -1359,6 +1413,12 @@ function apply(ctx, config) {
|
|
|
1359
1413
|
remainingPurchasedCount: userData.remainingPurchasedCount,
|
|
1360
1414
|
isAdmin: userManager.isAdmin(userId, config)
|
|
1361
1415
|
});
|
|
1416
|
+
try {
|
|
1417
|
+
const statsMessage = buildStatsMessage(userData, numImages, consumptionType, freeUsed, purchasedUsed, config);
|
|
1418
|
+
await session.send(statsMessage);
|
|
1419
|
+
} catch (error) {
|
|
1420
|
+
logger.warn("发送统计信息失败", { userId, error: sanitizeError(error) });
|
|
1421
|
+
}
|
|
1362
1422
|
}
|
|
1363
1423
|
__name(recordUserUsage, "recordUserUsage");
|
|
1364
1424
|
async function recordSecurityBlock(session, numImages = 1) {
|
|
@@ -1467,7 +1527,7 @@ function apply(ctx, config) {
|
|
|
1467
1527
|
return { images: collectedImages, text: collectedText };
|
|
1468
1528
|
}
|
|
1469
1529
|
__name(getInputData, "getInputData");
|
|
1470
|
-
async function requestProviderImages(prompt, imageUrls, numImages, requestContext) {
|
|
1530
|
+
async function requestProviderImages(prompt, imageUrls, numImages, requestContext, onImageGenerated) {
|
|
1471
1531
|
const providerType = requestContext?.provider || config.provider;
|
|
1472
1532
|
const targetModelId = requestContext?.modelId;
|
|
1473
1533
|
const providerInstance = getProviderInstance(providerType, targetModelId);
|
|
@@ -1478,7 +1538,7 @@ function apply(ctx, config) {
|
|
|
1478
1538
|
numImages
|
|
1479
1539
|
});
|
|
1480
1540
|
}
|
|
1481
|
-
return await providerInstance.generateImages(prompt, imageUrls, numImages);
|
|
1541
|
+
return await providerInstance.generateImages(prompt, imageUrls, numImages, onImageGenerated);
|
|
1482
1542
|
}
|
|
1483
1543
|
__name(requestProviderImages, "requestProviderImages");
|
|
1484
1544
|
async function processImageWithTimeout(session, img, prompt, styleName, requestContext, displayInfo, mode = "single") {
|
|
@@ -1493,7 +1553,6 @@ function apply(ctx, config) {
|
|
|
1493
1553
|
}, config.commandTimeout * 1e3)
|
|
1494
1554
|
)
|
|
1495
1555
|
]).catch(async (error) => {
|
|
1496
|
-
if (userId) userManager.endTask(userId);
|
|
1497
1556
|
const sanitizedError = sanitizeError(error);
|
|
1498
1557
|
logger.error("图像处理超时或失败", { userId, error: sanitizedError });
|
|
1499
1558
|
if (error?.message !== "命令执行超时") {
|
|
@@ -1575,20 +1634,38 @@ ${infoParts.join("\n")}`;
|
|
|
1575
1634
|
}
|
|
1576
1635
|
statusMessage += "...";
|
|
1577
1636
|
await session.send(statusMessage);
|
|
1578
|
-
const
|
|
1637
|
+
const generatedImages = [];
|
|
1638
|
+
let creditDeducted = false;
|
|
1639
|
+
const onImageGenerated = /* @__PURE__ */ __name(async (imageUrl, index, total) => {
|
|
1640
|
+
if (checkTimeout && checkTimeout()) {
|
|
1641
|
+
throw new Error("命令执行超时");
|
|
1642
|
+
}
|
|
1643
|
+
generatedImages.push(imageUrl);
|
|
1644
|
+
if (!creditDeducted && generatedImages.length > 0) {
|
|
1645
|
+
creditDeducted = true;
|
|
1646
|
+
await recordUserUsage(session, styleName, total);
|
|
1647
|
+
logger.info("流式处理:第一张图片生成,积分已扣除", {
|
|
1648
|
+
userId,
|
|
1649
|
+
totalImages: total,
|
|
1650
|
+
currentIndex: index
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
await session.send(import_koishi2.h.image(imageUrl));
|
|
1654
|
+
logger.debug("流式处理:图片已发送", { index: index + 1, total });
|
|
1655
|
+
if (total > 1 && index < total - 1) {
|
|
1656
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1657
|
+
}
|
|
1658
|
+
}, "onImageGenerated");
|
|
1659
|
+
const images = await requestProviderImages(finalPrompt, imageUrls, imageCount, requestContext, onImageGenerated);
|
|
1579
1660
|
if (checkTimeout && checkTimeout()) throw new Error("命令执行超时");
|
|
1580
1661
|
if (images.length === 0) {
|
|
1581
1662
|
return "图像处理失败:未能生成图片";
|
|
1582
1663
|
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
await session.send(import_koishi2.h.image(images[i]));
|
|
1587
|
-
if (images.length > 1 && i < images.length - 1) {
|
|
1588
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1589
|
-
}
|
|
1664
|
+
if (!creditDeducted) {
|
|
1665
|
+
await recordUserUsage(session, styleName, images.length);
|
|
1666
|
+
logger.warn("流式处理:积分在最后扣除(异常情况)", { userId, imagesCount: images.length });
|
|
1590
1667
|
}
|
|
1591
|
-
await
|
|
1668
|
+
await session.send("图像处理完成!");
|
|
1592
1669
|
} finally {
|
|
1593
1670
|
userManager.endTask(userId);
|
|
1594
1671
|
}
|
|
@@ -1610,7 +1687,8 @@ ${infoParts.join("\n")}`;
|
|
|
1610
1687
|
}
|
|
1611
1688
|
const userPromptText = userPromptParts.join(" - ");
|
|
1612
1689
|
const numImages = options?.num || config.defaultNumImages;
|
|
1613
|
-
const
|
|
1690
|
+
const userName = session.username || session.userId || "未知用户";
|
|
1691
|
+
const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
|
|
1614
1692
|
if (!limitCheck.allowed) {
|
|
1615
1693
|
return limitCheck.message;
|
|
1616
1694
|
}
|
|
@@ -1646,7 +1724,8 @@ ${infoParts.join("\n")}`;
|
|
|
1646
1724
|
ctx.command(`${COMMANDS.TXT_TO_IMG} [prompt:text]`, "根据文字描述生成图像").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async ({ session, options }, prompt) => {
|
|
1647
1725
|
if (!session?.userId) return "会话无效";
|
|
1648
1726
|
const numImages = options?.num || config.defaultNumImages;
|
|
1649
|
-
const
|
|
1727
|
+
const userName = session.username || session.userId || "未知用户";
|
|
1728
|
+
const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
|
|
1650
1729
|
if (!limitCheck.allowed) {
|
|
1651
1730
|
return limitCheck.message;
|
|
1652
1731
|
}
|
|
@@ -1659,7 +1738,8 @@ ${infoParts.join("\n")}`;
|
|
|
1659
1738
|
if (!session?.userId) return "会话无效";
|
|
1660
1739
|
const numImages = options?.num || config.defaultNumImages;
|
|
1661
1740
|
const mode = options?.multiple ? "multiple" : "single";
|
|
1662
|
-
const
|
|
1741
|
+
const userName = session.username || session.userId || "未知用户";
|
|
1742
|
+
const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
|
|
1663
1743
|
if (!limitCheck.allowed) {
|
|
1664
1744
|
return limitCheck.message;
|
|
1665
1745
|
}
|
|
@@ -1674,11 +1754,9 @@ ${infoParts.join("\n")}`;
|
|
|
1674
1754
|
if (!userManager.startTask(userId)) {
|
|
1675
1755
|
return "您有一个图像处理任务正在进行中,请等待完成";
|
|
1676
1756
|
}
|
|
1677
|
-
userManager.endTask(userId);
|
|
1678
1757
|
let isTimeout = false;
|
|
1679
1758
|
return Promise.race([
|
|
1680
1759
|
(async () => {
|
|
1681
|
-
if (!userManager.startTask(userId)) return "您有一个图像处理任务正在进行中";
|
|
1682
1760
|
try {
|
|
1683
1761
|
await session.send("多张图片+描述");
|
|
1684
1762
|
const collectedImages = [];
|
|
@@ -1723,7 +1801,8 @@ ${infoParts.join("\n")}`;
|
|
|
1723
1801
|
if (imageCount < 1 || imageCount > 4) {
|
|
1724
1802
|
return "生成数量必须在 1-4 之间";
|
|
1725
1803
|
}
|
|
1726
|
-
const
|
|
1804
|
+
const userName = session.username || userId || "未知用户";
|
|
1805
|
+
const limitCheck = await userManager.checkAndReserveQuota(userId, userName, imageCount, config);
|
|
1727
1806
|
if (!limitCheck.allowed) {
|
|
1728
1807
|
return limitCheck.message;
|
|
1729
1808
|
}
|
|
@@ -1737,20 +1816,38 @@ ${infoParts.join("\n")}`;
|
|
|
1737
1816
|
});
|
|
1738
1817
|
await session.send(`开始合成图(${collectedImages.length}张)...
|
|
1739
1818
|
Prompt: ${prompt}`);
|
|
1740
|
-
const
|
|
1819
|
+
const generatedImages = [];
|
|
1820
|
+
let creditDeducted = false;
|
|
1821
|
+
const onImageGenerated = /* @__PURE__ */ __name(async (imageUrl, index, total) => {
|
|
1822
|
+
if (isTimeout) {
|
|
1823
|
+
throw new Error("命令执行超时");
|
|
1824
|
+
}
|
|
1825
|
+
generatedImages.push(imageUrl);
|
|
1826
|
+
if (!creditDeducted && generatedImages.length > 0) {
|
|
1827
|
+
creditDeducted = true;
|
|
1828
|
+
await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, total);
|
|
1829
|
+
logger.info("流式处理:第一张图片生成,积分已扣除", {
|
|
1830
|
+
userId,
|
|
1831
|
+
totalImages: total,
|
|
1832
|
+
currentIndex: index
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
await session.send(import_koishi2.h.image(imageUrl));
|
|
1836
|
+
logger.debug("流式处理:图片已发送", { index: index + 1, total });
|
|
1837
|
+
if (total > 1 && index < total - 1) {
|
|
1838
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1839
|
+
}
|
|
1840
|
+
}, "onImageGenerated");
|
|
1841
|
+
const resultImages = await requestProviderImages(prompt, collectedImages, imageCount, void 0, onImageGenerated);
|
|
1741
1842
|
if (isTimeout) throw new Error("命令执行超时");
|
|
1742
1843
|
if (resultImages.length === 0) {
|
|
1743
1844
|
return "图片合成失败:未能生成图片";
|
|
1744
1845
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
await session.send(import_koishi2.h.image(resultImages[i]));
|
|
1749
|
-
if (resultImages.length > 1 && i < resultImages.length - 1) {
|
|
1750
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1751
|
-
}
|
|
1846
|
+
if (!creditDeducted) {
|
|
1847
|
+
await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, resultImages.length);
|
|
1848
|
+
logger.warn("流式处理:积分在最后扣除(异常情况)", { userId, imagesCount: resultImages.length });
|
|
1752
1849
|
}
|
|
1753
|
-
await
|
|
1850
|
+
await session.send("图片合成完成!");
|
|
1754
1851
|
} finally {
|
|
1755
1852
|
userManager.endTask(userId);
|
|
1756
1853
|
}
|
|
@@ -1762,7 +1859,6 @@ Prompt: ${prompt}`);
|
|
|
1762
1859
|
}, config.commandTimeout * 1e3)
|
|
1763
1860
|
)
|
|
1764
1861
|
]).catch(async (error) => {
|
|
1765
|
-
if (userId) userManager.endTask(userId);
|
|
1766
1862
|
const sanitizedError = sanitizeError(error);
|
|
1767
1863
|
logger.error("图片合成超时或失败", { userId, error: sanitizedError });
|
|
1768
1864
|
if (error?.message !== "命令执行超时") {
|
|
@@ -7,5 +7,5 @@ export interface GeminiConfig extends ProviderConfig {
|
|
|
7
7
|
export declare class GeminiProvider implements ImageProvider {
|
|
8
8
|
private config;
|
|
9
9
|
constructor(config: GeminiConfig);
|
|
10
|
-
generateImages(prompt: string, imageUrls: string | string[], numImages: number): Promise<string[]>;
|
|
10
|
+
generateImages(prompt: string, imageUrls: string | string[], numImages: number, onImageGenerated?: (imageUrl: string, index: number, total: number) => void | Promise<void>): Promise<string[]>;
|
|
11
11
|
}
|
|
@@ -6,5 +6,5 @@ export interface GptGodConfig extends ProviderConfig {
|
|
|
6
6
|
export declare class GptGodProvider implements ImageProvider {
|
|
7
7
|
private config;
|
|
8
8
|
constructor(config: GptGodConfig);
|
|
9
|
-
generateImages(prompt: string, imageUrls: string | string[], numImages: number): Promise<string[]>;
|
|
9
|
+
generateImages(prompt: string, imageUrls: string | string[], numImages: number, onImageGenerated?: (imageUrl: string, index: number, total: number) => void | Promise<void>): Promise<string[]>;
|
|
10
10
|
}
|
package/lib/providers/types.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ export interface ImageProvider {
|
|
|
4
4
|
* @param prompt 提示词
|
|
5
5
|
* @param imageUrls 输入图片 URL 数组
|
|
6
6
|
* @param numImages 需要生成的图片数量
|
|
7
|
+
* @param onImageGenerated 可选的回调函数,每生成一张图片时调用(用于流式处理)
|
|
7
8
|
* @returns 生成的图片 URL 数组(data: URL 或 http URL)
|
|
8
9
|
*/
|
|
9
|
-
generateImages(prompt: string, imageUrls: string | string[], numImages: number): Promise<string[]>;
|
|
10
|
+
generateImages(prompt: string, imageUrls: string | string[], numImages: number, onImageGenerated?: (imageUrl: string, index: number, total: number) => void | Promise<void>): Promise<string[]>;
|
|
10
11
|
}
|
|
11
12
|
export interface ProviderConfig {
|
|
12
13
|
apiTimeout: number;
|
|
@@ -74,6 +74,11 @@ export declare class UserManager {
|
|
|
74
74
|
message?: string;
|
|
75
75
|
isAdmin?: boolean;
|
|
76
76
|
}>;
|
|
77
|
+
checkAndReserveQuota(userId: string, userName: string, numImages: number, config: Config): Promise<{
|
|
78
|
+
allowed: boolean;
|
|
79
|
+
message?: string;
|
|
80
|
+
reservationId?: string;
|
|
81
|
+
}>;
|
|
77
82
|
consumeQuota(userId: string, userName: string, commandName: string, numImages: number, config: Config): Promise<{
|
|
78
83
|
userData: UserData;
|
|
79
84
|
consumptionType: 'free' | 'purchased' | 'mixed';
|