koishi-plugin-p-draw 1.0.0 → 1.1.0
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 +58 -3
- package/package.json +1 -1
- package/readme.md +2 -0
package/index.js
CHANGED
|
@@ -75,6 +75,10 @@ const zhCN = {
|
|
|
75
75
|
couponPrice: { $description: '提示词优化券单价(P 点/张,购买询问时显示)' },
|
|
76
76
|
couponAskTimeout: { $description: '提示词优化券确认等待时间(秒)' },
|
|
77
77
|
img2imgDenoise: { $description: '以图生图(p-draw i2i)的去噪强度,越小越接近原图(建议 0.4-0.7)' },
|
|
78
|
+
taggerEnabled: { $description: 'i2i 前自动识图(需 ComfyUI 安装 WD14 Tagger 节点与模型;识别出的标签会注入提示词优化)' },
|
|
79
|
+
taggerModel: { $description: '识图模型名(WD14 Tagger 节点里可选模型)' },
|
|
80
|
+
taggerThreshold: { $description: '识图标签置信度阈值' },
|
|
81
|
+
taggerCharacterThreshold: { $description: '识图角色标签置信度阈值' },
|
|
78
82
|
adminUsers: { $description: '免 P 点管理员用户 ID 列表' },
|
|
79
83
|
outputLogs: { $description: '是否在控制台输出详细日志' },
|
|
80
84
|
multiVerifyEnabled: { $description: '多人图生成后启用视觉校验(需配置下方视觉模型)' },
|
|
@@ -211,6 +215,10 @@ exports.Config = Schema.object({
|
|
|
211
215
|
couponPrice: Schema.number().default(3000).description('提示词优化券单价(P 点/张,购买询问时显示;可自动读取 data/p-shop.json 里的价格覆盖)'),
|
|
212
216
|
couponAskTimeout: Schema.number().default(60).description('提示词优化券确认等待时间(秒)'),
|
|
213
217
|
img2imgDenoise: Schema.number().default(0.55).description('以图生图(p-draw i2i)的去噪强度,越小越接近原图(建议 0.4-0.7)'),
|
|
218
|
+
taggerEnabled: Schema.boolean().default(false).description('i2i 前自动识图(需 ComfyUI 安装 WD14 Tagger 节点与模型;识别出的标签会注入提示词优化)'),
|
|
219
|
+
taggerModel: Schema.string().default('wd-v1-4-convnext-tagger-v2').description('识图模型名(WD14 Tagger 节点里可选模型)'),
|
|
220
|
+
taggerThreshold: Schema.number().default(0.35).description('识图标签置信度阈值'),
|
|
221
|
+
taggerCharacterThreshold: Schema.number().default(0.85).description('识图角色标签置信度阈值'),
|
|
214
222
|
adminUsers: Schema.array(Schema.string()).default([]).description('免 P 点管理员用户 ID 列表'),
|
|
215
223
|
outputLogs: Schema.boolean().default(true).description('是否在控制台输出详细日志'),
|
|
216
224
|
|
|
@@ -2875,7 +2883,51 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2875
2883
|
return session.text('.i2i-upload-fail', [e.message])
|
|
2876
2884
|
}
|
|
2877
2885
|
if (cfg.outputLogs) logger.info(`[p-draw] i2i ${session.userId} 原图已上传:${uploadName}`)
|
|
2878
|
-
|
|
2886
|
+
// 识图:仅当启用、非无优化模式、且已配置 LLM(识图结果会注入提示词优化)时才执行
|
|
2887
|
+
let taggerTags = ''
|
|
2888
|
+
if (cfg.taggerEnabled && cfg.llmModel && cfg.llmBaseUrl && !stripRawPrefix(rawText).raw) {
|
|
2889
|
+
try {
|
|
2890
|
+
taggerTags = await taggerImage(uploadName)
|
|
2891
|
+
if (cfg.outputLogs) logger.info(`[p-draw] i2i ${session.userId} 识图完成:${taggerTags.slice(0, 120)}${taggerTags.length > 120 ? '...' : ''}`)
|
|
2892
|
+
} catch (e) {
|
|
2893
|
+
logger.warn(`识图失败(继续生图):${e.message}`)
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
return await handleGenerate(session, rawText, uploadName, taggerTags)
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
// 识图预工作流:LoadImage → WD14Tagger|pysssss,读回原图 tags
|
|
2900
|
+
async function taggerImage(uploadName) {
|
|
2901
|
+
const model = String(cfg.taggerModel || 'wd-v1-4-convnext-tagger-v2').trim()
|
|
2902
|
+
const taggerNodeId = '61'
|
|
2903
|
+
const promptBody = {
|
|
2904
|
+
'60': { class_type: 'LoadImage', inputs: { image: uploadName } },
|
|
2905
|
+
[taggerNodeId]: {
|
|
2906
|
+
class_type: 'WD14Tagger|pysssss',
|
|
2907
|
+
inputs: {
|
|
2908
|
+
image: ['60', 0],
|
|
2909
|
+
model,
|
|
2910
|
+
threshold: Number(cfg.taggerThreshold) || 0.35,
|
|
2911
|
+
character_threshold: Number(cfg.taggerCharacterThreshold) || 0.85,
|
|
2912
|
+
replace_underscore: true,
|
|
2913
|
+
trailing_comma: false,
|
|
2914
|
+
exclude_tags: '',
|
|
2915
|
+
},
|
|
2916
|
+
},
|
|
2917
|
+
}
|
|
2918
|
+
const clientId = crypto.randomUUID()
|
|
2919
|
+
const submit = await comfyPost('/prompt', { prompt: promptBody, client_id: clientId }, 20000)
|
|
2920
|
+
const promptId = submit && submit.prompt_id
|
|
2921
|
+
if (!promptId) throw new Error('识图工作流提交失败')
|
|
2922
|
+
const timeoutMs = Math.max(1, parseInt(cfg.timeout) || 300) * 1000
|
|
2923
|
+
const pollMs = Math.max(1, parseInt(cfg.pollInterval) || 2) * 1000
|
|
2924
|
+
const history = await waitComfyResult(ctx, comfyGet, baseUrl(), promptId, clientId, timeoutMs, pollMs)
|
|
2925
|
+
if (!history) throw new Error('识图超时')
|
|
2926
|
+
const nodeOutput = history.outputs && history.outputs[taggerNodeId]
|
|
2927
|
+
const tags = (nodeOutput && Array.isArray(nodeOutput.tags) ? nodeOutput.tags : []).filter(Boolean)
|
|
2928
|
+
const first = String(tags[0] || '').trim()
|
|
2929
|
+
if (!first) throw new Error('识图未返回标签')
|
|
2930
|
+
return first
|
|
2879
2931
|
}
|
|
2880
2932
|
|
|
2881
2933
|
// 从会话消息里取第一张图片并下载为内存 Buffer
|
|
@@ -2925,12 +2977,15 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
2925
2977
|
return data.name
|
|
2926
2978
|
}
|
|
2927
2979
|
|
|
2928
|
-
async function handleGenerate(session, rawText, i2iImage = null) {
|
|
2980
|
+
async function handleGenerate(session, rawText, i2iImage = null, taggerTags = '') {
|
|
2929
2981
|
const USERID = session.userId
|
|
2930
2982
|
const isAdmin = isAdminUser(session)
|
|
2931
2983
|
const unet = await resolveUnet(USERID)
|
|
2932
2984
|
const i2iRule = i2iImage
|
|
2933
2985
|
? '这是以图生图(img2img):原图的构图、主体与色调会被保留。请主要描述你希望发生的变化(风格、服装、表情、场景改造、细节调整等),不要重复描述原图已有的细节。'
|
|
2986
|
+
+ (taggerTags
|
|
2987
|
+
? `\n\n原图内容参考(本地识图自动识别出的标签,用于了解原图已包含的内容;不要照抄全部标签,只参考与用户改动需求相关的部分):\n${taggerTags}`
|
|
2988
|
+
: '')
|
|
2934
2989
|
: ''
|
|
2935
2990
|
if (cfg.outputLogs) {
|
|
2936
2991
|
logger.info(`[p-draw] 请求 userId=${USERID} isAdmin=${isAdmin} adminUsers=${JSON.stringify(cfg.adminUsers || [])} normalizeId=${normalizeId(USERID)}`)
|
|
@@ -3283,5 +3338,5 @@ exports.apply = async function apply(ctx, cfg) {
|
|
|
3283
3338
|
})
|
|
3284
3339
|
|
|
3285
3340
|
// 暴露内部接口供自动化测试调用(Koishi 忽略 apply 返回值,不影响生产行为)
|
|
3286
|
-
return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, animaI2IWorkflow }
|
|
3341
|
+
return { couponConfirmFlow, buyCouponsAndConsume, normalizeConfirm, resolveCouponPrice, handleGenerateI2I, extractImageFromSession, uploadImageToComfyui, taggerImage, animaI2IWorkflow }
|
|
3287
3342
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -15,6 +15,7 @@ p点-绘图插件,连接本地 ComfyUI 生图,参考 AstrBot 的 [anima 绘
|
|
|
15
15
|
- 画师组管理(创建 / 追加 / 切换 / 查看 / 删除)。
|
|
16
16
|
- 固定角色(`添加角色 名称=tags`)。
|
|
17
17
|
- **以图生图**:`p-draw i2i <描述>` 并在同一条消息附一张原图(文件 / 截图 / 链接均可),保留原图构图与主体,按描述调整风格与细节。使用 ComfyUI 内置 `LoadImage → VAEEncode → KSampler(denoise<1)` 标准节点,**无需修改 ComfyUI**;去噪强度由 `img2imgDenoise` 控制(默认 0.55,越小越接近原图)。不支持自定义工作流(`customWorkflowEnabled`)时使用 i2i 会提示关闭。
|
|
18
|
+
- **i2i 自动识图**:配置 `taggerEnabled` 后,i2i 会先通过 ComfyUI 的 **WD14 Tagger** 节点对原图识图,把识别出的标签注入提示词优化,让不支持读图的 LLM(如 DeepSeek)也能"看到"原图内容。需要在 ComfyUI `custom_nodes` 安装 [ComfyUI-WD14-Tagger](https://github.com/pythongosssss/ComfyUI-WD14-Tagger),并把模型 `.onnx` + `.csv` 放进 `custom_nodes/ComfyUI-WD14-Tagger/models/`(模型名由 `taggerModel` 指定,默认 `wd-v1-4-convnext-tagger-v2`)。仅当已配置 LLM(`llmBaseUrl`/`llmModel`)且非 `无优化` 模式时才会识图;识图失败会跳过并正常生图。
|
|
18
19
|
- **用户自选模型**:`p-draw 模型` 查看当前与可用模型(自动读取 ComfyUI 的 UNET 列表),`p-draw 模型 <名称>` 切换(支持模糊匹配,如 `anima-aesthetic`),`p-draw 模型 默认` 恢复默认。偏好按用户保存(`p_draw_config.user_models`),单人 / 多人 / 连续图都生效;未自选时用 `unetName` 默认模型。自定义工作流(`customWorkflowEnabled`)不参与模型切换。
|
|
19
20
|
- 画师组与固定角色**保存在数据库 `p_draw_config` 表中**,管理指令不触发插件重载(不会打断正在生成的图,也不会把配置恢复成默认)。数据库中的值在重启后覆盖配置里的同名项。
|
|
20
21
|
- 自定义 ComfyUI 工作流 JSON。
|
|
@@ -76,6 +77,7 @@ plugins:
|
|
|
76
77
|
| `fixedCharacters` / `artistPresets` / `activeArtistPreset` / `styleTags` | 角色、画师组与画风 |
|
|
77
78
|
| `queueEnabled` / `queueMaxRequests` | 生成队列 |
|
|
78
79
|
| `img2imgDenoise` | 以图生图(`p-draw i2i`)去噪强度,默认 0.55(建议 0.4-0.7,越小越接近原图) |
|
|
80
|
+
| `taggerEnabled` / `taggerModel` / `taggerThreshold` / `taggerCharacterThreshold` | i2i 自动识图开关、识图模型名、标签阈值 / 角色标签阈值(需 ComfyUI 安装 WD14 Tagger 节点与模型) |
|
|
79
81
|
| `couponPrice` / `couponAskTimeout` | 提示词优化券单价(P 点/张,默认 3000,可被 `data/p-shop.json` 覆盖)与交互确认等待时间(秒,默认 60) |
|
|
80
82
|
| `batchMax` | 单次指令最多生成的张数(`x3` / `3张` / `--数量 3` 等写法),默认 4 |
|
|
81
83
|
| `price` / `multiPrice` / `adminUsers` | 单张 / 多人单张消耗的 P 点与免单管理员 |
|