koishi-plugin-p-draw 1.3.1 → 1.3.2

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.
Files changed (2) hide show
  1. package/index.js +56 -47
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -461,43 +461,46 @@ exports.apply = async function apply(ctx, cfg) {
461
461
  return { ok: true, tasks, firstPosition }
462
462
  }
463
463
 
464
- // 即时反馈的公共部分(队列/生成中 + 张数 + 扣费),返回待发送的行
465
- function feedbackBase(session, { firstPosition, count, totalPrice, isAdmin }) {
466
- const rows = []
467
- if (cfg.queueEnabled) {
468
- rows.push(session.text('.queued', [firstPosition, cfg.queueMaxRequests || '∞']))
469
- if (count > 1) rows.push(session.text('.batch-count', [count]))
470
- if (!isAdmin) rows.push(session.text('.charged', [totalPrice]))
471
- } else {
472
- rows.push(session.text('.generating'))
473
- if (count > 1) rows.push(session.text('.batch-count', [count]))
474
- if (!isAdmin) rows.push(session.text('.charged', [totalPrice]))
475
- }
476
- return rows
477
- }
478
-
479
- async function sendNotices(session, notices) {
480
- if (!notices.length) return
481
- try {
482
- await session.send(notices.filter(Boolean).join('\n'))
483
- } catch (e) {
484
- logger.warn(`发送反馈消息失败:${e.message}`)
485
- }
486
- }
487
-
488
- // 发图:引用用户触发指令的原消息,失败回退普通发送
489
- async function sendImagesWithQuote(session, outputs) {
464
+ // 即时反馈的公共部分。扣费提醒单独返回,随后以引用消息发送。
465
+ function feedbackBase(session, { firstPosition, count, totalPrice, isAdmin }) {
466
+ const notices = []
467
+ if (cfg.queueEnabled) {
468
+ notices.push(session.text('.queued', [firstPosition, cfg.queueMaxRequests || '∞']))
469
+ if (count > 1) notices.push(session.text('.batch-count', [count]))
470
+ } else {
471
+ notices.push(session.text('.generating'))
472
+ if (count > 1) notices.push(session.text('.batch-count', [count]))
473
+ }
474
+ return {
475
+ notices,
476
+ chargeNotice: isAdmin ? '' : session.text('.charged', [totalPrice]),
477
+ }
478
+ }
479
+
480
+ async function sendNotices(session, notices, opts = {}) {
481
+ const content = notices.filter(Boolean).join('\n')
482
+ if (!content) return
483
+ try {
484
+ const message = opts.quote && session.messageId ? h.quote(session.messageId) + content : content
485
+ await session.send(message)
486
+ } catch (e) {
487
+ logger.warn(`发送反馈消息失败:${e.message}`)
488
+ }
489
+ }
490
+
491
+ // 生成图片使用合并转发;不附原消息引用。发送失败时回退普通图片消息。
492
+ async function sendImagesAsForward(session, outputs) {
490
493
  const imageElements = await Promise.all(outputs.map(async (src) => {
491
494
  const materialized = await materializeImageSource(src)
492
495
  return Buffer.isBuffer(materialized) ? h.image(materialized) : h.image(src)
493
496
  }))
494
- try {
495
- await session.send(h.quote(session.messageId) + imageElements.join(''))
496
- } catch (e) {
497
- logger.warn(`发送图片失败(引用):${e.message}`)
498
- await session.send(imageElements)
499
- }
500
- }
497
+ try {
498
+ await session.send(h('figure', imageElements))
499
+ } catch (e) {
500
+ logger.warn(`发送转发图片失败:${e.message}`)
501
+ await session.send(imageElements)
502
+ }
503
+ }
501
504
 
502
505
  // P 点读改写按用户串行化,避免并发指令互相覆盖余额
503
506
  const userLocks = new Map()
@@ -1449,8 +1452,10 @@ exports.apply = async function apply(ctx, cfg) {
1449
1452
  // 即时反馈
1450
1453
  const notice = []
1451
1454
  if (parsedBatch.clamped) notice.push(session.text('.batch-limit', [count]))
1452
- notice.push(...feedbackBase(session, { firstPosition, count, totalPrice: count * price, isAdmin }))
1453
- await sendNotices(session, notice)
1455
+ const feedback = feedbackBase(session, { firstPosition, count, totalPrice: count * price, isAdmin })
1456
+ notice.push(...feedback.notices)
1457
+ await sendNotices(session, notice)
1458
+ await sendNotices(session, [feedback.chargeNotice], { quote: true })
1454
1459
 
1455
1460
  // 单张生成 +(可选)视觉校验
1456
1461
  const runOne = async (i) => {
@@ -1493,8 +1498,8 @@ exports.apply = async function apply(ctx, cfg) {
1493
1498
 
1494
1499
  if (cfg.outputLogs) logger.success(`${USERID} 多人生成成功 ${successCount}/${count} 张`)
1495
1500
 
1496
- // 发图:引用用户触发指令的原消息
1497
- await sendImagesWithQuote(session, allOutputs)
1501
+ // 发图:合并转发,不引用原指令
1502
+ await sendImagesAsForward(session, allOutputs)
1498
1503
 
1499
1504
  const reply = []
1500
1505
  if (count > 1) {
@@ -1625,8 +1630,10 @@ exports.apply = async function apply(ctx, cfg) {
1625
1630
  if (identity && fixedChars[identity]) notice.push(`已固定角色「${identity}」的身份 tags,各阶段外观将保持一致。`)
1626
1631
  if (!useLLM) notice.push(session.text('.series-no-llm'))
1627
1632
  if (degradedStages) notice.push(session.text('.prompt-degraded', ['(连续图阶段优化失败,已使用原始描述)']))
1628
- notice.push(...feedbackBase(session, { firstPosition, count, totalPrice: count * price, isAdmin }))
1629
- await sendNotices(session, notice)
1633
+ const feedback = feedbackBase(session, { firstPosition, count, totalPrice: count * price, isAdmin })
1634
+ notice.push(...feedback.notices)
1635
+ await sendNotices(session, notice)
1636
+ await sendNotices(session, [feedback.chargeNotice], { quote: true })
1630
1637
 
1631
1638
  // 单阶段生成(共用 seed)
1632
1639
  const runOne = async (i) => {
@@ -1661,8 +1668,8 @@ exports.apply = async function apply(ctx, cfg) {
1661
1668
 
1662
1669
  if (cfg.outputLogs) logger.success(`${USERID} 连续图生成成功 ${successCount}/${count} 阶段(seed=${seed})`)
1663
1670
 
1664
- // 发图:引用用户触发指令的原消息
1665
- await sendImagesWithQuote(session, allOutputs)
1671
+ // 发图:合并转发,不引用原指令
1672
+ await sendImagesAsForward(session, allOutputs)
1666
1673
 
1667
1674
  const reply = []
1668
1675
  reply.push(session.text('.series-ok', [count * price, successCount, seed]))
@@ -2330,8 +2337,10 @@ exports.apply = async function apply(ctx, cfg) {
2330
2337
  notice.push(session.text('.no-optimize', [reasons[noOptimizeReason] || noOptimizeReason]))
2331
2338
  }
2332
2339
  if (parsedBatch.clamped) notice.push(session.text('.batch-limit', [count]))
2333
- notice.push(...feedbackBase(session, { firstPosition, count, totalPrice: count * cfg.price, isAdmin }))
2334
- await sendNotices(session, notice)
2340
+ const feedback = feedbackBase(session, { firstPosition, count, totalPrice: count * cfg.price, isAdmin })
2341
+ notice.push(...feedback.notices)
2342
+ await sendNotices(session, notice)
2343
+ await sendNotices(session, [feedback.chargeNotice], { quote: true })
2335
2344
 
2336
2345
  // 单张生成
2337
2346
  const runOne = async (i) => {
@@ -2371,8 +2380,8 @@ exports.apply = async function apply(ctx, cfg) {
2371
2380
 
2372
2381
  if (cfg.outputLogs) logger.success(`${USERID} 生成成功 ${successCount}/${count} 张`)
2373
2382
 
2374
- // 发图:引用用户触发指令的原消息
2375
- await sendImagesWithQuote(session, allOutputs)
2383
+ // 发图:合并转发,不引用原指令
2384
+ await sendImagesAsForward(session, allOutputs)
2376
2385
 
2377
2386
  const reply = []
2378
2387
  if (count > 1) {
@@ -2525,5 +2534,5 @@ exports.apply = async function apply(ctx, cfg) {
2525
2534
  })
2526
2535
 
2527
2536
  // 暴露内部接口供自动化测试调用(Koishi 忽略 apply 返回值,不影响生产行为)
2528
- return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, taggerImage, animaI2IWorkflow, animaStyleI2IWorkflow, animaOotdI2IWorkflow, buildI2IWorkflow, detectI2ICapabilities, parseDenoise }
2529
- }
2537
+ return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, taggerImage, animaI2IWorkflow, animaStyleI2IWorkflow, animaOotdI2IWorkflow, buildI2IWorkflow, detectI2ICapabilities, parseDenoise, sendNotices, sendImagesAsForward }
2538
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-p-draw",
3
3
  "description": "p点-绘图,连接本地 ComfyUI 生图。支持自然语言优化、尺寸选择、画师组、固定角色、生成队列,需要配合 p-qiandao 使用",
4
- "version": "1.3.1",
4
+ "version": "1.3.2",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "index.js",