koishi-plugin-p-draw 1.3.5 → 1.3.6
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 +31 -28
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -488,21 +488,21 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
//
|
|
491
|
+
// 生成图片使用合并转发;每张图后紧跟实际使用的正负面提示词,不附原消息引用。
|
|
492
492
|
async function sendImagesAsForward(session, outputs) {
|
|
493
493
|
const nodes = []
|
|
494
494
|
const fallback = []
|
|
495
495
|
for (const output of outputs) {
|
|
496
496
|
const src = typeof output === 'string' ? output : output.src
|
|
497
497
|
const prompt = typeof output === 'string' ? '' : String(output.prompt || '')
|
|
498
|
+
const negativePrompt = typeof output === 'string' ? '' : String(output.negativePrompt || '')
|
|
498
499
|
const materialized = await materializeImageSource(src)
|
|
499
500
|
const image = Buffer.isBuffer(materialized) ? h.image(materialized) : h.image(src)
|
|
500
501
|
nodes.push(h('message', image))
|
|
501
502
|
fallback.push(image)
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
503
|
+
const promptText = `Positive:\n${prompt}\n\nNegative:\n${negativePrompt}`
|
|
504
|
+
nodes.push(h('message', promptText))
|
|
505
|
+
fallback.push(promptText)
|
|
506
506
|
}
|
|
507
507
|
try {
|
|
508
508
|
await session.send(h('figure', nodes))
|
|
@@ -664,9 +664,10 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
664
664
|
width,
|
|
665
665
|
height,
|
|
666
666
|
steps,
|
|
667
|
-
cfg: cfgVal,
|
|
668
|
-
prompt_id: promptId,
|
|
669
|
-
|
|
667
|
+
cfg: cfgVal,
|
|
668
|
+
prompt_id: promptId,
|
|
669
|
+
negativePrompt,
|
|
670
|
+
}
|
|
670
671
|
}
|
|
671
672
|
|
|
672
673
|
// ---------------- LLM 提示词优化 ----------------
|
|
@@ -1195,11 +1196,11 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1195
1196
|
|
|
1196
1197
|
// 视觉校验(anima_verify + generation_verifier 移植):对生成的图片跑视觉 LLM,
|
|
1197
1198
|
// 不合格则用相同提示词重试(最多 multiCandidateCount 张),按多候选规则挑选并返回结果。
|
|
1198
|
-
async function verifyGeneratedImages(session, images, userRequest, prompt, size, planCount, unet) {
|
|
1199
|
+
async function verifyGeneratedImages(session, images, userRequest, prompt, size, planCount, unet, negativePrompt) {
|
|
1199
1200
|
const verifyBaseUrl = String(cfg.verifyLlmBaseUrl || '').trim()
|
|
1200
1201
|
const verifyModel = String(cfg.verifyLlmModel || '').trim()
|
|
1201
1202
|
if (!verifyBaseUrl || !verifyModel) {
|
|
1202
|
-
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt }
|
|
1203
|
+
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt, negativePrompt }
|
|
1203
1204
|
}
|
|
1204
1205
|
const passScore = Math.max(0, Math.min(10, parseInt(cfg.multiVerifyPassScore) || 6))
|
|
1205
1206
|
const candidateCount = Math.max(1, Math.min(3, parseInt(cfg.multiCandidateCount) || 2))
|
|
@@ -1207,9 +1208,10 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1207
1208
|
const systemPrompt = buildVerifySystemPrompt(true, planCount)
|
|
1208
1209
|
const candidates = []
|
|
1209
1210
|
let lastVerdict = null
|
|
1210
|
-
let retries = 0
|
|
1211
|
-
let currentImages = images
|
|
1212
|
-
let currentPrompt = prompt
|
|
1211
|
+
let retries = 0
|
|
1212
|
+
let currentImages = images
|
|
1213
|
+
let currentPrompt = prompt
|
|
1214
|
+
let currentNegativePrompt = negativePrompt
|
|
1213
1215
|
|
|
1214
1216
|
async function verifyOnce(imgs, userReq) {
|
|
1215
1217
|
const controller = new AbortController()
|
|
@@ -1307,15 +1309,15 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1307
1309
|
data = extractVerifyJson(reply)
|
|
1308
1310
|
} catch (e) {
|
|
1309
1311
|
logger.warn(`多人视觉校验失败:${e.message}`)
|
|
1310
|
-
return { ok: true, degraded: true, message: session.text('.multi-verify-error', [String(e && e.message || e)]), verdict: null, outputs: images, prompt: currentPrompt }
|
|
1312
|
+
return { ok: true, degraded: true, message: session.text('.multi-verify-error', [String(e && e.message || e)]), verdict: null, outputs: images, prompt: currentPrompt, negativePrompt: currentNegativePrompt }
|
|
1311
1313
|
}
|
|
1312
1314
|
if (!data) {
|
|
1313
1315
|
logger.warn(`多人视觉校验返回无法解析:${reply.slice(0, 200)}`)
|
|
1314
|
-
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt: currentPrompt }
|
|
1316
|
+
return { ok: true, degraded: true, message: '', verdict: null, outputs: images, prompt: currentPrompt, negativePrompt: currentNegativePrompt }
|
|
1315
1317
|
}
|
|
1316
1318
|
const verdict = verdictFromData(data)
|
|
1317
1319
|
verdict.skipped = false
|
|
1318
|
-
candidates.push({ outputs: currentImages, verdict, prompt: currentPrompt })
|
|
1320
|
+
candidates.push({ outputs: currentImages, verdict, prompt: currentPrompt, negativePrompt: currentNegativePrompt })
|
|
1319
1321
|
selectedOutputs = currentImages
|
|
1320
1322
|
selectedVerdict = verdict
|
|
1321
1323
|
|
|
@@ -1329,12 +1331,13 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1329
1331
|
if (hint) {
|
|
1330
1332
|
currentPrompt = `${userRequest}\n【上次问题,请修正】${hint}`
|
|
1331
1333
|
}
|
|
1332
|
-
const regen = await runComfyGenerate(currentPrompt, size, { unet })
|
|
1334
|
+
const regen = await runComfyGenerate(currentPrompt, size, { unet, negativePrompt: currentNegativePrompt })
|
|
1333
1335
|
if (!regen.ok) {
|
|
1334
1336
|
logger.warn(`多人校验重试生成失败:${regen.message}`)
|
|
1335
1337
|
break
|
|
1336
1338
|
}
|
|
1337
|
-
currentImages = regen.outputs
|
|
1339
|
+
currentImages = regen.outputs
|
|
1340
|
+
currentNegativePrompt = regen.negativePrompt || currentNegativePrompt
|
|
1338
1341
|
}
|
|
1339
1342
|
|
|
1340
1343
|
// 多候选挑选
|
|
@@ -1345,7 +1348,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1345
1348
|
selectedOutputs = best.outputs
|
|
1346
1349
|
selectedVerdict = best.verdict
|
|
1347
1350
|
if (!multiAccepted && !cfg.multiSendDegradedCandidate) {
|
|
1348
|
-
return { ok: false, discarded: true, message: session.text('.multi-verify-discarded'), verdict: selectedVerdict, outputs: [], prompt: best.prompt }
|
|
1351
|
+
return { ok: false, discarded: true, message: session.text('.multi-verify-discarded'), verdict: selectedVerdict, outputs: [], prompt: best.prompt, negativePrompt: best.negativePrompt }
|
|
1349
1352
|
}
|
|
1350
1353
|
const noteParts = []
|
|
1351
1354
|
if (multiAccepted) {
|
|
@@ -1354,7 +1357,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1354
1357
|
noteParts.push(session.text('.multi-verify-degraded', selectedVerdict.issues.length ? '(' + selectedVerdict.issues.join(';').slice(0, 80) + ')' : ''))
|
|
1355
1358
|
}
|
|
1356
1359
|
if (retries) noteParts.push(session.text('.multi-verify-failed', [selectedVerdict.issues.length ? ':' + selectedVerdict.issues.join(';').slice(0, 80) : '', retries]))
|
|
1357
|
-
return { ok: true, degraded: false, message: noteParts.join('\n'), verdict: selectedVerdict, outputs: selectedOutputs, prompt: best.prompt }
|
|
1360
|
+
return { ok: true, degraded: false, message: noteParts.join('\n'), verdict: selectedVerdict, outputs: selectedOutputs, prompt: best.prompt, negativePrompt: best.negativePrompt }
|
|
1358
1361
|
}
|
|
1359
1362
|
|
|
1360
1363
|
function buildVerifySystemPrompt(multiPerson, planCount) {
|
|
@@ -1367,7 +1370,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1367
1370
|
}
|
|
1368
1371
|
|
|
1369
1372
|
// 共享批量执行器:一次性扣除总价,逐张生成,单张失败只退该张单价。
|
|
1370
|
-
// runOne(i) 需返回 { ok, outputs, seed, prompt, message? };返回数组为多张输出(如视觉校验候选)。
|
|
1373
|
+
// runOne(i) 需返回 { ok, outputs, seed, prompt, negativePrompt, message? };返回数组为多张输出(如视觉校验候选)。
|
|
1371
1374
|
async function executeBatch(USERID, isAdmin, count, unitPrice, runOne) {
|
|
1372
1375
|
const results = []
|
|
1373
1376
|
let successCount = 0
|
|
@@ -1381,7 +1384,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1381
1384
|
const outputs = Array.isArray(item.outputs) ? item.outputs : (item.outputs ? [item.outputs] : [])
|
|
1382
1385
|
if (item.ok && outputs.length) {
|
|
1383
1386
|
successCount += 1
|
|
1384
|
-
results.push({ i, ok: true, outputs, seed: item.seed, prompt: item.prompt || '', note: item.note || '' })
|
|
1387
|
+
results.push({ i, ok: true, outputs, seed: item.seed, prompt: item.prompt || '', negativePrompt: item.negativePrompt || '', note: item.note || '' })
|
|
1385
1388
|
} else {
|
|
1386
1389
|
if (!isAdmin) await refundP(USERID, unitPrice)
|
|
1387
1390
|
if (cfg.outputLogs) logger.warn(`批量第 ${i + 1} 张生成失败(${USERID}):${item.message || '无输出'}`)
|
|
@@ -1477,11 +1480,11 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1477
1480
|
}
|
|
1478
1481
|
if (!result.ok || !result.outputs || !result.outputs.length) return result
|
|
1479
1482
|
if (!cfg.multiVerifyEnabled) {
|
|
1480
|
-
return { ok: true, outputs: result.outputs, seed: result.seed, prompt: finalPrompt, note: session.text('.multi-degraded', ['(未启用校验或未配置视觉模型)']) }
|
|
1483
|
+
return { ok: true, outputs: result.outputs, seed: result.seed, prompt: finalPrompt, negativePrompt: result.negativePrompt, note: session.text('.multi-degraded', ['(未启用校验或未配置视觉模型)']) }
|
|
1481
1484
|
}
|
|
1482
|
-
const verified = await verifyGeneratedImages(session, result.outputs, text, finalPrompt, size, plan.characters.length, unet)
|
|
1485
|
+
const verified = await verifyGeneratedImages(session, result.outputs, text, finalPrompt, size, plan.characters.length, unet, result.negativePrompt || multiNegative)
|
|
1483
1486
|
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 || '' }
|
|
1487
|
+
return { ok: true, outputs: verified.outputs, seed: result.seed, prompt: verified.prompt || finalPrompt, negativePrompt: verified.negativePrompt || result.negativePrompt || multiNegative, note: verified.message || '' }
|
|
1485
1488
|
}
|
|
1486
1489
|
|
|
1487
1490
|
const { results, successCount } = await executeBatch(USERID, isAdmin, count, price, runOne)
|
|
@@ -1495,7 +1498,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1495
1498
|
for (const item of results) {
|
|
1496
1499
|
if (item.ok) {
|
|
1497
1500
|
allOutputs.push(...item.outputs)
|
|
1498
|
-
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt })))
|
|
1501
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt, negativePrompt: item.negativePrompt })))
|
|
1499
1502
|
if (item.seed != null) seeds.push(item.seed)
|
|
1500
1503
|
if (item.note) notes.push(item.note)
|
|
1501
1504
|
} else {
|
|
@@ -1669,7 +1672,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
1669
1672
|
for (const item of results) {
|
|
1670
1673
|
if (item.ok) {
|
|
1671
1674
|
allOutputs.push(...item.outputs)
|
|
1672
|
-
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || stagePrompts[item.i] || '' })))
|
|
1675
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || stagePrompts[item.i] || '', negativePrompt: item.negativePrompt })))
|
|
1673
1676
|
if (item.seed != null) seeds.push(item.seed)
|
|
1674
1677
|
} else {
|
|
1675
1678
|
failures.push(`第 ${item.i + 1} 阶段:${item.message}`)
|
|
@@ -2393,7 +2396,7 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2393
2396
|
for (const item of results) {
|
|
2394
2397
|
if (item.ok) {
|
|
2395
2398
|
allOutputs.push(...item.outputs)
|
|
2396
|
-
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt })))
|
|
2399
|
+
forwardOutputs.push(...item.outputs.map(src => ({ src, prompt: item.prompt || finalPrompt, negativePrompt: item.negativePrompt })))
|
|
2397
2400
|
if (item.seed != null) seeds.push(item.seed)
|
|
2398
2401
|
} else {
|
|
2399
2402
|
failures.push(`第 ${item.i + 1} 张:${item.message}`)
|