koishi-plugin-p-draw 1.3.2 → 1.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/index.js +72 -53
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -488,17 +488,27 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
//
|
|
491
|
+
// 生成图片使用合并转发;每张图后紧跟实际使用的最终提示词,不附原消息引用。
|
|
492
492
|
async function sendImagesAsForward(session, outputs) {
|
|
493
|
-
const
|
|
493
|
+
const nodes = []
|
|
494
|
+
const fallback = []
|
|
495
|
+
for (const output of outputs) {
|
|
496
|
+
const src = typeof output === 'string' ? output : output.src
|
|
497
|
+
const prompt = typeof output === 'string' ? '' : String(output.prompt || '')
|
|
494
498
|
const materialized = await materializeImageSource(src)
|
|
495
|
-
|
|
496
|
-
|
|
499
|
+
const image = Buffer.isBuffer(materialized) ? h.image(materialized) : h.image(src)
|
|
500
|
+
nodes.push(h('message', image))
|
|
501
|
+
fallback.push(image)
|
|
502
|
+
if (prompt) {
|
|
503
|
+
nodes.push(h('message', prompt))
|
|
504
|
+
fallback.push(prompt)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
497
507
|
try {
|
|
498
|
-
await session.send(h('figure',
|
|
508
|
+
await session.send(h('figure', nodes))
|
|
499
509
|
} catch (e) {
|
|
500
510
|
logger.warn(`发送转发图片失败:${e.message}`)
|
|
501
|
-
await session.send(
|
|
511
|
+
await session.send(fallback)
|
|
502
512
|
}
|
|
503
513
|
}
|
|
504
514
|
|
|
@@ -1189,7 +1199,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1189
1199
|
const verifyBaseUrl = String(cfg.verifyLlmBaseUrl || '').trim()
|
|
1190
1200
|
const verifyModel = String(cfg.verifyLlmModel || '').trim()
|
|
1191
1201
|
if (!verifyBaseUrl || !verifyModel) {
|
|
1192
|
-
return { ok: true, degraded: true, message: '', verdict: null, outputs: images }
|
|
1202
|
+
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt }
|
|
1193
1203
|
}
|
|
1194
1204
|
const passScore = Math.max(0, Math.min(10, parseInt(cfg.multiVerifyPassScore) || 6))
|
|
1195
1205
|
const candidateCount = Math.max(1, Math.min(3, parseInt(cfg.multiCandidateCount) || 2))
|
|
@@ -1297,11 +1307,11 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1297
1307
|
data = extractVerifyJson(reply)
|
|
1298
1308
|
} catch (e) {
|
|
1299
1309
|
logger.warn(`多人视觉校验失败:${e.message}`)
|
|
1300
|
-
return { ok: true, degraded: true, message: session.text('.multi-verify-error', [String(e && e.message || e)]), verdict: null, outputs: images }
|
|
1310
|
+
return { ok: true, degraded: true, message: session.text('.multi-verify-error', [String(e && e.message || e)]), verdict: null, outputs: images, prompt: currentPrompt }
|
|
1301
1311
|
}
|
|
1302
1312
|
if (!data) {
|
|
1303
1313
|
logger.warn(`多人视觉校验返回无法解析:${reply.slice(0, 200)}`)
|
|
1304
|
-
return { ok: true, degraded: true, message: '', verdict: null, outputs: images }
|
|
1314
|
+
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt: currentPrompt }
|
|
1305
1315
|
}
|
|
1306
1316
|
const verdict = verdictFromData(data)
|
|
1307
1317
|
verdict.skipped = false
|
|
@@ -1335,7 +1345,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1335
1345
|
selectedOutputs = best.outputs
|
|
1336
1346
|
selectedVerdict = best.verdict
|
|
1337
1347
|
if (!multiAccepted && !cfg.multiSendDegradedCandidate) {
|
|
1338
|
-
return { ok: false, discarded: true, message: session.text('.multi-verify-discarded'), verdict: selectedVerdict, outputs: [] }
|
|
1348
|
+
return { ok: false, discarded: true, message: session.text('.multi-verify-discarded'), verdict: selectedVerdict, outputs: [], prompt: best.prompt }
|
|
1339
1349
|
}
|
|
1340
1350
|
const noteParts = []
|
|
1341
1351
|
if (multiAccepted) {
|
|
@@ -1344,7 +1354,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1344
1354
|
noteParts.push(session.text('.multi-verify-degraded', selectedVerdict.issues.length ? '(' + selectedVerdict.issues.join(';').slice(0, 80) + ')' : ''))
|
|
1345
1355
|
}
|
|
1346
1356
|
if (retries) noteParts.push(session.text('.multi-verify-failed', [selectedVerdict.issues.length ? ':' + selectedVerdict.issues.join(';').slice(0, 80) : '', retries]))
|
|
1347
|
-
return { ok: true, degraded: false, message: noteParts.join('\n'), verdict: selectedVerdict, outputs: selectedOutputs }
|
|
1357
|
+
return { ok: true, degraded: false, message: noteParts.join('\n'), verdict: selectedVerdict, outputs: selectedOutputs, prompt: best.prompt }
|
|
1348
1358
|
}
|
|
1349
1359
|
|
|
1350
1360
|
function buildVerifySystemPrompt(multiPerson, planCount) {
|
|
@@ -1357,7 +1367,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1357
1367
|
}
|
|
1358
1368
|
|
|
1359
1369
|
// 共享批量执行器:一次性扣除总价,逐张生成,单张失败只退该张单价。
|
|
1360
|
-
// runOne(i) 需返回 { ok, outputs, seed, message? };返回数组为多张输出(如视觉校验候选)。
|
|
1370
|
+
// runOne(i) 需返回 { ok, outputs, seed, prompt, message? };返回数组为多张输出(如视觉校验候选)。
|
|
1361
1371
|
async function executeBatch(USERID, isAdmin, count, unitPrice, runOne) {
|
|
1362
1372
|
const results = []
|
|
1363
1373
|
let successCount = 0
|
|
@@ -1371,7 +1381,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1371
1381
|
const outputs = Array.isArray(item.outputs) ? item.outputs : (item.outputs ? [item.outputs] : [])
|
|
1372
1382
|
if (item.ok && outputs.length) {
|
|
1373
1383
|
successCount += 1
|
|
1374
|
-
results.push({ i, ok: true, outputs, seed: item.seed, note: item.note || '' })
|
|
1384
|
+
results.push({ i, ok: true, outputs, seed: item.seed, prompt: item.prompt || '', note: item.note || '' })
|
|
1375
1385
|
} else {
|
|
1376
1386
|
if (!isAdmin) await refundP(USERID, unitPrice)
|
|
1377
1387
|
if (cfg.outputLogs) logger.warn(`批量第 ${i + 1} 张生成失败(${USERID}):${item.message || '无输出'}`)
|
|
@@ -1465,25 +1475,27 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1465
1475
|
} else {
|
|
1466
1476
|
try { result = await runComfyGenerate(finalPrompt, size, { negativePrompt: multiNegative, unet }) } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
1467
1477
|
}
|
|
1468
|
-
if (!result.ok || !result.outputs || !result.outputs.length) return result
|
|
1469
|
-
if (!cfg.multiVerifyEnabled) {
|
|
1470
|
-
return { ok: true, outputs: result.outputs, seed: result.seed, note: session.text('.multi-degraded', ['(未启用校验或未配置视觉模型)']) }
|
|
1471
|
-
}
|
|
1472
|
-
const verified = await verifyGeneratedImages(session, result.outputs, text, finalPrompt, size, plan.characters.length, unet)
|
|
1473
|
-
if (!verified.ok) return { ok: false, message: verified.message }
|
|
1474
|
-
return { ok: true, outputs: verified.outputs, seed: result.seed, note: verified.message || '' }
|
|
1478
|
+
if (!result.ok || !result.outputs || !result.outputs.length) return result
|
|
1479
|
+
if (!cfg.multiVerifyEnabled) {
|
|
1480
|
+
return { ok: true, outputs: result.outputs, seed: result.seed, prompt: finalPrompt, note: session.text('.multi-degraded', ['(未启用校验或未配置视觉模型)']) }
|
|
1481
|
+
}
|
|
1482
|
+
const verified = await verifyGeneratedImages(session, result.outputs, text, finalPrompt, size, plan.characters.length, unet)
|
|
1483
|
+
if (!verified.ok) return { ok: false, message: verified.message }
|
|
1484
|
+
return { ok: true, outputs: verified.outputs, seed: result.seed, prompt: verified.prompt || finalPrompt, note: verified.message || '' }
|
|
1475
1485
|
}
|
|
1476
1486
|
|
|
1477
1487
|
const { results, successCount } = await executeBatch(USERID, isAdmin, count, price, runOne)
|
|
1478
1488
|
|
|
1479
|
-
// 汇总
|
|
1480
|
-
const allOutputs = []
|
|
1481
|
-
const
|
|
1489
|
+
// 汇总
|
|
1490
|
+
const allOutputs = []
|
|
1491
|
+
const forwardOutputs = []
|
|
1492
|
+
const notes = []
|
|
1482
1493
|
const seeds = []
|
|
1483
1494
|
const failures = []
|
|
1484
1495
|
for (const item of results) {
|
|
1485
|
-
if (item.ok) {
|
|
1486
|
-
allOutputs.push(...item.outputs)
|
|
1496
|
+
if (item.ok) {
|
|
1497
|
+
allOutputs.push(...item.outputs)
|
|
1498
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt })))
|
|
1487
1499
|
if (item.seed != null) seeds.push(item.seed)
|
|
1488
1500
|
if (item.note) notes.push(item.note)
|
|
1489
1501
|
} else {
|
|
@@ -1499,7 +1511,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1499
1511
|
if (cfg.outputLogs) logger.success(`${USERID} 多人生成成功 ${successCount}/${count} 张`)
|
|
1500
1512
|
|
|
1501
1513
|
// 发图:合并转发,不引用原指令
|
|
1502
|
-
await sendImagesAsForward(session,
|
|
1514
|
+
await sendImagesAsForward(session, forwardOutputs)
|
|
1503
1515
|
|
|
1504
1516
|
const reply = []
|
|
1505
1517
|
if (count > 1) {
|
|
@@ -1638,23 +1650,26 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1638
1650
|
// 单阶段生成(共用 seed)
|
|
1639
1651
|
const runOne = async (i) => {
|
|
1640
1652
|
let result
|
|
1641
|
-
if (cfg.queueEnabled) {
|
|
1642
|
-
try { result = await queuedTasks[i] } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
1643
|
-
} else {
|
|
1644
|
-
try { result = await runComfyGenerate(stagePrompts[i], size, { seed, unet }) } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1653
|
+
if (cfg.queueEnabled) {
|
|
1654
|
+
try { result = await queuedTasks[i] } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
1655
|
+
} else {
|
|
1656
|
+
try { result = await runComfyGenerate(stagePrompts[i], size, { seed, unet }) } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
1657
|
+
}
|
|
1658
|
+
result.prompt = stagePrompts[i]
|
|
1659
|
+
return result
|
|
1647
1660
|
}
|
|
1648
1661
|
|
|
1649
1662
|
const { results, successCount } = await executeBatch(USERID, isAdmin, count, price, runOne)
|
|
1650
1663
|
|
|
1651
|
-
// 汇总
|
|
1652
|
-
const allOutputs = []
|
|
1653
|
-
const
|
|
1664
|
+
// 汇总
|
|
1665
|
+
const allOutputs = []
|
|
1666
|
+
const forwardOutputs = []
|
|
1667
|
+
const seeds = []
|
|
1654
1668
|
const failures = []
|
|
1655
1669
|
for (const item of results) {
|
|
1656
|
-
if (item.ok) {
|
|
1657
|
-
allOutputs.push(...item.outputs)
|
|
1670
|
+
if (item.ok) {
|
|
1671
|
+
allOutputs.push(...item.outputs)
|
|
1672
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || stagePrompts[item.i] || '' })))
|
|
1658
1673
|
if (item.seed != null) seeds.push(item.seed)
|
|
1659
1674
|
} else {
|
|
1660
1675
|
failures.push(`第 ${item.i + 1} 阶段:${item.message}`)
|
|
@@ -1669,7 +1684,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1669
1684
|
if (cfg.outputLogs) logger.success(`${USERID} 连续图生成成功 ${successCount}/${count} 阶段(seed=${seed})`)
|
|
1670
1685
|
|
|
1671
1686
|
// 发图:合并转发,不引用原指令
|
|
1672
|
-
await sendImagesAsForward(session,
|
|
1687
|
+
await sendImagesAsForward(session, forwardOutputs)
|
|
1673
1688
|
|
|
1674
1689
|
const reply = []
|
|
1675
1690
|
reply.push(session.text('.series-ok', [count * price, successCount, seed]))
|
|
@@ -2314,7 +2329,8 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2314
2329
|
const optimized = await optimizePrompt(session, userPrompt, true, i2iRule, searchCache)
|
|
2315
2330
|
p = appendInlineProtectedTags(composePrompt(optimized.prompt || userPrompt, raw).prompt, userPrompt, raw)
|
|
2316
2331
|
}
|
|
2317
|
-
|
|
2332
|
+
const generated = await runComfyGenerate(p, parsedSize.size, Object.assign({ unet, seed }, i2iRun))
|
|
2333
|
+
return { ...generated, prompt: p }
|
|
2318
2334
|
}, { USERID, isAdmin, totalPrice: count * cfg.price })
|
|
2319
2335
|
if (!queued.ok) return queued.message
|
|
2320
2336
|
const queuedTasks = queued.tasks
|
|
@@ -2352,22 +2368,25 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2352
2368
|
let result
|
|
2353
2369
|
if (cfg.queueEnabled) {
|
|
2354
2370
|
try { result = await queuedTasks[i] } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
2355
|
-
} else {
|
|
2356
|
-
try { result = await runComfyGenerate(p, parsedSize.size, Object.assign({ unet, seed }, i2iRun)) } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2371
|
+
} else {
|
|
2372
|
+
try { result = await runComfyGenerate(p, parsedSize.size, Object.assign({ unet, seed }, i2iRun)) } catch (e) { result = { ok: false, message: `生成失败:${e.message}` } }
|
|
2373
|
+
}
|
|
2374
|
+
if (!result.prompt) result.prompt = p
|
|
2375
|
+
return result
|
|
2359
2376
|
}
|
|
2360
2377
|
|
|
2361
2378
|
const { results, successCount } = await executeBatch(USERID, isAdmin, count, cfg.price, runOne)
|
|
2362
2379
|
|
|
2363
|
-
// 汇总
|
|
2364
|
-
const allOutputs = []
|
|
2365
|
-
const
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2380
|
+
// 汇总
|
|
2381
|
+
const allOutputs = []
|
|
2382
|
+
const forwardOutputs = []
|
|
2383
|
+
const seeds = []
|
|
2384
|
+
const failures = []
|
|
2385
|
+
for (const item of results) {
|
|
2386
|
+
if (item.ok) {
|
|
2387
|
+
allOutputs.push(...item.outputs)
|
|
2388
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt })))
|
|
2389
|
+
if (item.seed != null) seeds.push(item.seed)
|
|
2371
2390
|
} else {
|
|
2372
2391
|
failures.push(`第 ${item.i + 1} 张:${item.message}`)
|
|
2373
2392
|
}
|
|
@@ -2381,7 +2400,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2381
2400
|
if (cfg.outputLogs) logger.success(`${USERID} 生成成功 ${successCount}/${count} 张`)
|
|
2382
2401
|
|
|
2383
2402
|
// 发图:合并转发,不引用原指令
|
|
2384
|
-
await sendImagesAsForward(session,
|
|
2403
|
+
await sendImagesAsForward(session, forwardOutputs)
|
|
2385
2404
|
|
|
2386
2405
|
const reply = []
|
|
2387
2406
|
if (count > 1) {
|
|
@@ -2534,5 +2553,5 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2534
2553
|
})
|
|
2535
2554
|
|
|
2536
2555
|
// 暴露内部接口供自动化测试调用(Koishi 忽略 apply 返回值,不影响生产行为)
|
|
2537
|
-
return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, taggerImage, animaI2IWorkflow, animaStyleI2IWorkflow, animaOotdI2IWorkflow, buildI2IWorkflow, detectI2ICapabilities, parseDenoise, sendNotices, sendImagesAsForward }
|
|
2556
|
+
return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, taggerImage, animaI2IWorkflow, animaStyleI2IWorkflow, animaOotdI2IWorkflow, buildI2IWorkflow, detectI2ICapabilities, parseDenoise, sendNotices, sendImagesAsForward, executeBatch }
|
|
2538
2557
|
}
|