koishi-plugin-hhs-huatu 0.3.2 → 0.3.3

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
@@ -471,9 +471,6 @@ async function login(ctx, email, password) {
471
471
  let startIndex = ctx.runtime.currentTokenIndex;
472
472
  let strategy = ctx.config.tokenStrategy || "round-robin";
473
473
  logger.debug(`使用token策略: ${strategy}`);
474
- if (strategy === "parallel" && !ctx.runtime.tokenUsage) {
475
- ctx.runtime.tokenUsage = {};
476
- }
477
474
  if (strategy === "random") {
478
475
  startIndex = Math.floor(Math.random() * ctx.config.token.length);
479
476
  ctx.runtime.currentTokenIndex = startIndex;
@@ -481,9 +478,9 @@ async function login(ctx, email, password) {
481
478
  let foundUnusedToken = false;
482
479
  for (let i = 0; i < ctx.config.token.length; i++) {
483
480
  const checkIndex = (ctx.runtime.currentTokenIndex + i) % ctx.config.token.length;
484
- if (!ctx.runtime.tokenUsage[checkIndex]) {
481
+ const tokenUsage = ctx.runtime.tokenUsage || {};
482
+ if (!tokenUsage[checkIndex]) {
485
483
  startIndex = checkIndex;
486
- ctx.runtime.tokenUsage[checkIndex] = true;
487
484
  ctx.runtime.currentTokenIndex = (checkIndex + 1) % ctx.config.token.length;
488
485
  foundUnusedToken = true;
489
486
  logger.debug(`并行策略选择token索引 ${checkIndex},下一次从索引 ${ctx.runtime.currentTokenIndex} 开始检查`);
@@ -1523,12 +1520,19 @@ __name(auditImage, "auditImage");
1523
1520
 
1524
1521
  // src/queueSystem.ts
1525
1522
  var QueueSystem = class {
1526
- constructor(ctx, config, generateImageFn, membershipSystem) {
1523
+ constructor(ctx, config, generateImageFn, membershipSystem, initialTokenUsage) {
1527
1524
  this.ctx = ctx;
1528
1525
  this.config = config;
1529
1526
  this.generateImageFn = generateImageFn;
1530
1527
  this.membershipSystem = membershipSystem || null;
1531
1528
  this.maxConcurrentTasks = config.tokenStrategy === "parallel" && Array.isArray(config.token) ? Math.min(config.maxConcurrentRequests || 1, config.token.length) : config.maxConcurrentRequests || 1;
1529
+ if (initialTokenUsage) {
1530
+ this.tokenUsage = { ...initialTokenUsage };
1531
+ } else if (config.tokenStrategy === "parallel" && Array.isArray(config.token)) {
1532
+ for (let i = 0; i < config.token.length; i++) {
1533
+ this.tokenUsage[i] = false;
1534
+ }
1535
+ }
1532
1536
  }
1533
1537
  static {
1534
1538
  __name(this, "QueueSystem");
@@ -1552,6 +1556,9 @@ var QueueSystem = class {
1552
1556
  maxConcurrentTasks;
1553
1557
  // 会员系统引用
1554
1558
  membershipSystem = null;
1559
+ // Token管理相关
1560
+ tokenLock = Promise.resolve();
1561
+ tokenUsage = /* @__PURE__ */ Object.create(null);
1555
1562
  // 获取锁
1556
1563
  async acquireRedrawLock() {
1557
1564
  if (!this.redrawLock) {
@@ -1589,6 +1596,20 @@ var QueueSystem = class {
1589
1596
  this.usedTokenIndices.add(newIndex);
1590
1597
  return newIndex;
1591
1598
  }
1599
+ // 获取token锁,确保token选择的原子性
1600
+ async acquireTokenLock() {
1601
+ const release = this.tokenLock;
1602
+ let releaseFn = null;
1603
+ this.tokenLock = new Promise((resolve3) => {
1604
+ releaseFn = resolve3;
1605
+ });
1606
+ await release;
1607
+ return () => {
1608
+ if (releaseFn) {
1609
+ releaseFn();
1610
+ }
1611
+ };
1612
+ }
1592
1613
  // 处理队列
1593
1614
  async processQueue() {
1594
1615
  if (this.taskQueue.length === 0) return;
@@ -1596,10 +1617,8 @@ var QueueSystem = class {
1596
1617
  const tasksToProcess = Math.min(this.maxConcurrentTasks - this.processingTasks, this.taskQueue.length);
1597
1618
  if (this.config.tokenStrategy === "parallel" && Array.isArray(this.ctx.config.token)) {
1598
1619
  this.ctx.logger.debug(`处理队列中的任务,当前处理中: ${this.processingTasks},即将处理: ${tasksToProcess},队列剩余: ${this.taskQueue.length},最大并发: ${this.maxConcurrentTasks}`);
1599
- if (this.ctx.runtime?.tokenUsage) {
1600
- const usedTokens = Object.entries(this.ctx.runtime.tokenUsage).filter(([_, used]) => used).map(([index]) => index);
1601
- this.ctx.logger.debug(`当前token使用情况: 已用 ${usedTokens.length}/${this.ctx.config.token.length} (索引: ${usedTokens.join(", ")})`);
1602
- }
1620
+ const usedTokens = Object.entries(this.tokenUsage).filter(([_, used]) => used).map(([index]) => index);
1621
+ this.ctx.logger.debug(`当前token使用情况: 已用 ${usedTokens.length}/${this.ctx.config.token.length} (索引: ${usedTokens.join(", ")})`);
1603
1622
  }
1604
1623
  for (let i = 0; i < tasksToProcess; i++) {
1605
1624
  this.processingTasks++;
@@ -1625,6 +1644,7 @@ var QueueSystem = class {
1625
1644
  }
1626
1645
  }
1627
1646
  Promise.resolve().then(async () => {
1647
+ const releaseTokenLock = await this.acquireTokenLock();
1628
1648
  try {
1629
1649
  const result = await this.generateImageFn(task.session, task.options, task.input);
1630
1650
  task.resolve(result);
@@ -1632,9 +1652,10 @@ var QueueSystem = class {
1632
1652
  task.reject(err);
1633
1653
  } finally {
1634
1654
  this.processingTasks--;
1655
+ releaseTokenLock();
1635
1656
  if (Array.isArray(this.ctx.config.token)) {
1636
- if (this.config.tokenStrategy === "parallel" && this.ctx.runtime?.tokenUsage) {
1637
- const usedTokens = Object.entries(this.ctx.runtime.tokenUsage).filter(([_, used]) => used).map(([index]) => index);
1657
+ if (this.config.tokenStrategy === "parallel") {
1658
+ const usedTokens = Object.entries(this.tokenUsage).filter(([_, used]) => used).map(([index]) => index);
1638
1659
  this.ctx.logger.debug(`任务完成后token使用情况(parallel): 已用 ${usedTokens.length}/${this.ctx.config.token.length} (索引: ${usedTokens.join(", ")})`);
1639
1660
  } else if (this.config.tokenStrategy === "round-robin") {
1640
1661
  this.ctx.logger.debug(`任务完成后token索引(round-robin): ${this.ctx.runtime?.currentTokenIndex}/${this.ctx.config.token.length - 1}`);
@@ -2168,6 +2189,16 @@ function apply(ctx, config) {
2168
2189
  const tasks = /* @__PURE__ */ Object.create(null);
2169
2190
  const globalTasks = /* @__PURE__ */ new Set();
2170
2191
  let queueSystem;
2192
+ const syncTokenUsage = /* @__PURE__ */ __name(() => {
2193
+ if (ctx.runtime && Array.isArray(ctx.config.token)) {
2194
+ if (!ctx.runtime.tokenUsage) {
2195
+ ctx.runtime.tokenUsage = {};
2196
+ for (let i = 0; i < ctx.config.token.length; i++) {
2197
+ ctx.runtime.tokenUsage[i] = false;
2198
+ }
2199
+ }
2200
+ }
2201
+ }, "syncTokenUsage");
2171
2202
  let tokenTask = null;
2172
2203
  const getToken = /* @__PURE__ */ __name(async (session) => {
2173
2204
  try {
@@ -2284,6 +2315,7 @@ function apply(ctx, config) {
2284
2315
  }
2285
2316
  return { width, height, custom: true };
2286
2317
  }, "resolution");
2318
+ syncTokenUsage();
2287
2319
  async function generateImage(session, options2, input) {
2288
2320
  ctx.logger.debug(`generateImage开始处理,sessionId=${session.id},userId=${session.userId}`);
2289
2321
  const sessionObj = session;
@@ -2940,7 +2972,7 @@ function apply(ctx, config) {
2940
2972
  }
2941
2973
  }
2942
2974
  __name(generateImage, "generateImage");
2943
- queueSystem = new QueueSystem(ctx, config, generateImage, membershipSystem);
2975
+ queueSystem = new QueueSystem(ctx, config, generateImage, membershipSystem, ctx.runtime?.tokenUsage);
2944
2976
  const cmd = ctx.command("novelai [prompts...]").alias("nai").alias("imagine").alias("nai4", { options: { model: "nai-v4-full", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4c", { options: { model: "nai-v4-curated-preview", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4-5c", { options: { model: "nai-v4-5-curated", sampler: "k_euler_a", iterations: 1, batch: 1 } }).alias("nai4-5", { options: { model: "nai-v4-5-full", sampler: "k_euler_a", iterations: 1, batch: 1 } }).userFields(["authority"]).shortcut("imagine", { i18n: true, fuzzy: true }).shortcut("enhance", { i18n: true, fuzzy: true, options: { enhance: true } }).option("enhance", "-e", { hidden: some(restricted, thirdParty, noImage) }).option("model", "-m <model>", { type: models, hidden: thirdParty }).option("resolution", "-r <resolution>", { type: resolution2 }).option("output", "-o", { type: ["minimal", "default", "verbose"] }).option("override", "-O", { hidden: restricted }).option("sampler", "-s <sampler>").option("seed", "-x <seed:number>").option("steps", "-t <step>", { type: step, hidden: restricted }).option("scale", "-c <scale:number>").option("rescale", "-R <rescale:number>").option("noise", "-n <noise:number>", { hidden: some(restricted, thirdParty) }).option("strength", "-N <strength:number>", { hidden: restricted }).option("hiresFix", "-H", { hidden: /* @__PURE__ */ __name(() => config.type !== "sd-webui", "hidden") }).option("hiresFixSteps", "<step>", { type: step, hidden: /* @__PURE__ */ __name(() => config.type !== "sd-webui", "hidden") }).option("smea", "-S", { hidden: /* @__PURE__ */ __name(() => config.model !== "nai-v3", "hidden") }).option("smeaDyn", "-d", { hidden: /* @__PURE__ */ __name(() => config.model !== "nai-v3", "hidden") }).option("scheduler", "-C <scheduler:string>", {
2945
2977
  hidden: /* @__PURE__ */ __name(() => config.type === "naifu", "hidden"),
2946
2978
  type: ["token", "login"].includes(config.type) ? scheduler.nai : config.type === "sd-webui" ? scheduler.sd : config.type === "stable-horde" ? scheduler.horde : []
@@ -3247,8 +3279,9 @@ function apply(ctx, config) {
3247
3279
  queueSystem.userTasks[currentUserId]--;
3248
3280
  targetBot.sendMessage(targetChannelId, value);
3249
3281
  if (Array.isArray(ctx.config.token)) {
3250
- if (config.tokenStrategy === "parallel" && ctx.runtime?.tokenUsage) {
3251
- const usedTokens = Object.entries(ctx.runtime.tokenUsage).filter(([_, used]) => used).map(([index2]) => index2);
3282
+ if (config.tokenStrategy === "parallel") {
3283
+ const queueTokenUsage = queueSystem.tokenUsage || {};
3284
+ const usedTokens = Object.entries(queueTokenUsage).filter(([_, used]) => used).map(([index2]) => index2);
3252
3285
  ctx.logger.debug(`重画任务 ${taskUniqueId} 完成,当前token使用情况: ${usedTokens.join(", ")}`);
3253
3286
  } else if (config.tokenStrategy === "round-robin") {
3254
3287
  ctx.logger.debug(`重画任务 ${taskUniqueId} 完成,当前token索引: ${ctx.runtime?.currentTokenIndex}`);
@@ -3266,8 +3299,9 @@ function apply(ctx, config) {
3266
3299
  handleError(ctx, session, err)
3267
3300
  );
3268
3301
  if (Array.isArray(ctx.config.token)) {
3269
- if (config.tokenStrategy === "parallel" && ctx.runtime?.tokenUsage) {
3270
- const usedTokens = Object.entries(ctx.runtime.tokenUsage).filter(([_, used]) => used).map(([index2]) => index2);
3302
+ if (config.tokenStrategy === "parallel") {
3303
+ const queueTokenUsage = queueSystem.tokenUsage || {};
3304
+ const usedTokens = Object.entries(queueTokenUsage).filter(([_, used]) => used).map(([index2]) => index2);
3271
3305
  ctx.logger.debug(`重画任务 ${taskUniqueId} 失败,当前token使用情况: ${usedTokens.join(", ")}`);
3272
3306
  } else if (config.tokenStrategy === "round-robin") {
3273
3307
  ctx.logger.debug(`重画任务 ${taskUniqueId} 失败,当前token索引: ${ctx.runtime?.currentTokenIndex}`);
@@ -28,10 +28,13 @@ export declare class QueueSystem {
28
28
  private redrawWaitQueue;
29
29
  maxConcurrentTasks: number;
30
30
  private membershipSystem;
31
- constructor(ctx: Context, config: Config, generateImageFn: (session: Session<'authority'>, options: any, input: string) => Promise<any>, membershipSystem?: MembershipSystem);
31
+ private tokenLock;
32
+ private tokenUsage;
33
+ constructor(ctx: Context, config: Config, generateImageFn: (session: Session<'authority'>, options: any, input: string) => Promise<any>, membershipSystem?: MembershipSystem, initialTokenUsage?: Dict<boolean>);
32
34
  acquireRedrawLock(): Promise<void>;
33
35
  releaseRedrawLock(): void;
34
36
  getUniqueTokenIndex(currentIndex: number, tokenCount: number): number;
37
+ private acquireTokenLock;
35
38
  processQueue(): Promise<void>;
36
39
  addTask(task: TaskQueueItem): Promise<any>;
37
40
  getQueueStatus(userId: string): {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-hhs-huatu",
3
3
  "description": "Generate images by diffusion models",
4
- "version": "0.3.2",
4
+ "version": "0.3.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [