koishi-plugin-aka-ai-generator 0.6.9 → 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 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
- allImages.push(...images);
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) : "未知错误";
@@ -1505,7 +1527,7 @@ function apply(ctx, config) {
1505
1527
  return { images: collectedImages, text: collectedText };
1506
1528
  }
1507
1529
  __name(getInputData, "getInputData");
1508
- async function requestProviderImages(prompt, imageUrls, numImages, requestContext) {
1530
+ async function requestProviderImages(prompt, imageUrls, numImages, requestContext, onImageGenerated) {
1509
1531
  const providerType = requestContext?.provider || config.provider;
1510
1532
  const targetModelId = requestContext?.modelId;
1511
1533
  const providerInstance = getProviderInstance(providerType, targetModelId);
@@ -1516,7 +1538,7 @@ function apply(ctx, config) {
1516
1538
  numImages
1517
1539
  });
1518
1540
  }
1519
- return await providerInstance.generateImages(prompt, imageUrls, numImages);
1541
+ return await providerInstance.generateImages(prompt, imageUrls, numImages, onImageGenerated);
1520
1542
  }
1521
1543
  __name(requestProviderImages, "requestProviderImages");
1522
1544
  async function processImageWithTimeout(session, img, prompt, styleName, requestContext, displayInfo, mode = "single") {
@@ -1612,21 +1634,38 @@ ${infoParts.join("\n")}`;
1612
1634
  }
1613
1635
  statusMessage += "...";
1614
1636
  await session.send(statusMessage);
1615
- const images = await requestProviderImages(finalPrompt, imageUrls, imageCount, requestContext);
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);
1616
1660
  if (checkTimeout && checkTimeout()) throw new Error("命令执行超时");
1617
1661
  if (images.length === 0) {
1618
1662
  return "图像处理失败:未能生成图片";
1619
1663
  }
1620
- await recordUserUsage(session, styleName, images.length);
1621
- if (checkTimeout && checkTimeout()) throw new Error("命令执行超时");
1622
- await session.send("图像处理完成!");
1623
- for (let i = 0; i < images.length; i++) {
1624
- if (checkTimeout && checkTimeout()) break;
1625
- await session.send(import_koishi2.h.image(images[i]));
1626
- if (images.length > 1 && i < images.length - 1) {
1627
- await new Promise((resolve) => setTimeout(resolve, 1e3));
1628
- }
1664
+ if (!creditDeducted) {
1665
+ await recordUserUsage(session, styleName, images.length);
1666
+ logger.warn("流式处理:积分在最后扣除(异常情况)", { userId, imagesCount: images.length });
1629
1667
  }
1668
+ await session.send("图像处理完成!");
1630
1669
  } finally {
1631
1670
  userManager.endTask(userId);
1632
1671
  }
@@ -1648,7 +1687,8 @@ ${infoParts.join("\n")}`;
1648
1687
  }
1649
1688
  const userPromptText = userPromptParts.join(" - ");
1650
1689
  const numImages = options?.num || config.defaultNumImages;
1651
- const limitCheck = await userManager.checkDailyLimit(session.userId, config, numImages);
1690
+ const userName = session.username || session.userId || "未知用户";
1691
+ const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
1652
1692
  if (!limitCheck.allowed) {
1653
1693
  return limitCheck.message;
1654
1694
  }
@@ -1684,7 +1724,8 @@ ${infoParts.join("\n")}`;
1684
1724
  ctx.command(`${COMMANDS.TXT_TO_IMG} [prompt:text]`, "根据文字描述生成图像").option("num", "-n <num:number> 生成图片数量 (1-4)").action(async ({ session, options }, prompt) => {
1685
1725
  if (!session?.userId) return "会话无效";
1686
1726
  const numImages = options?.num || config.defaultNumImages;
1687
- const limitCheck = await userManager.checkDailyLimit(session.userId, config, numImages);
1727
+ const userName = session.username || session.userId || "未知用户";
1728
+ const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
1688
1729
  if (!limitCheck.allowed) {
1689
1730
  return limitCheck.message;
1690
1731
  }
@@ -1697,7 +1738,8 @@ ${infoParts.join("\n")}`;
1697
1738
  if (!session?.userId) return "会话无效";
1698
1739
  const numImages = options?.num || config.defaultNumImages;
1699
1740
  const mode = options?.multiple ? "multiple" : "single";
1700
- const limitCheck = await userManager.checkDailyLimit(session.userId, config, numImages);
1741
+ const userName = session.username || session.userId || "未知用户";
1742
+ const limitCheck = await userManager.checkAndReserveQuota(session.userId, userName, numImages, config);
1701
1743
  if (!limitCheck.allowed) {
1702
1744
  return limitCheck.message;
1703
1745
  }
@@ -1759,7 +1801,8 @@ ${infoParts.join("\n")}`;
1759
1801
  if (imageCount < 1 || imageCount > 4) {
1760
1802
  return "生成数量必须在 1-4 之间";
1761
1803
  }
1762
- const limitCheck = await userManager.checkDailyLimit(userId, config, imageCount);
1804
+ const userName = session.username || userId || "未知用户";
1805
+ const limitCheck = await userManager.checkAndReserveQuota(userId, userName, imageCount, config);
1763
1806
  if (!limitCheck.allowed) {
1764
1807
  return limitCheck.message;
1765
1808
  }
@@ -1773,21 +1816,38 @@ ${infoParts.join("\n")}`;
1773
1816
  });
1774
1817
  await session.send(`开始合成图(${collectedImages.length}张)...
1775
1818
  Prompt: ${prompt}`);
1776
- const resultImages = await requestProviderImages(prompt, collectedImages, imageCount);
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);
1777
1842
  if (isTimeout) throw new Error("命令执行超时");
1778
1843
  if (resultImages.length === 0) {
1779
1844
  return "图片合成失败:未能生成图片";
1780
1845
  }
1781
- await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, resultImages.length);
1782
- if (isTimeout) throw new Error("命令执行超时");
1783
- await session.send("图片合成完成!");
1784
- for (let i = 0; i < resultImages.length; i++) {
1785
- if (isTimeout) break;
1786
- await session.send(import_koishi2.h.image(resultImages[i]));
1787
- if (resultImages.length > 1 && i < resultImages.length - 1) {
1788
- await new Promise((resolve) => setTimeout(resolve, 1e3));
1789
- }
1846
+ if (!creditDeducted) {
1847
+ await recordUserUsage(session, COMMANDS.COMPOSE_IMAGE, resultImages.length);
1848
+ logger.warn("流式处理:积分在最后扣除(异常情况)", { userId, imagesCount: resultImages.length });
1790
1849
  }
1850
+ await session.send("图片合成完成!");
1791
1851
  } finally {
1792
1852
  userManager.endTask(userId);
1793
1853
  }
@@ -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
  }
@@ -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;
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.6.9",
4
+ "version": "0.6.10",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [