koishi-plugin-p-draw 1.2.4 → 1.2.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.
Files changed (3) hide show
  1. package/index.js +32 -23
  2. package/package.json +1 -1
  3. package/readme.md +4 -4
package/index.js CHANGED
@@ -172,7 +172,7 @@ const zhCN = {
172
172
  'i2i-mode-cancelled': '已取消本次 i2i 生图。',
173
173
  'i2i-mode-style': '已选择【换风格(漫画化)】:保留原图构图,转成二次元画风。',
174
174
  'i2i-mode-ootd': '已选择【换装换姿势】:保留角色长相,重新设计服装/姿势/场景。',
175
- 'i2i-no-controlnet': '未检测到可用的 ControlNet 模型,本次「换风格」将使用普通 img2img,构图保留效果会弱一些。',
175
+ 'i2i-no-controlnet': '未检测到可用的 Anima ControlNet-LLLite,本次「换风格」将使用普通 img2img,构图保留效果会弱一些。',
176
176
  'i2i-no-ipadapter': '未检测到可用的 Anima IP-Adapter,本次「换装换姿势」将使用普通 img2img,角色保留效果会弱一些。',
177
177
  'multi-no-llm': '多人指令需要 LLM 规划,但当前未配置 llmBaseUrl / llmModel。请管理员在配置中填写后使用。',
178
178
  },
@@ -238,10 +238,10 @@ exports.Config = Schema.object({
238
238
  i2iAskTimeout: Schema.number().default(60).description('i2i 模式询问等待时间(秒)'),
239
239
  i2iStyleDenoise: Schema.number().default(0.75).description('换风格模式(漫画化)的去噪强度,越大风格变化越彻底(建议 0.7-0.85)'),
240
240
  i2iOotdDenoise: Schema.number().default(0.55).description('换装换姿势模式(保留角色)的去噪强度(建议 0.5-0.6)'),
241
- i2iControlNetStrength: Schema.number().default(0.7).description('换风格模式的 ControlNet 强度,越大构图锁得越死(建议 0.5-0.8'),
241
+ i2iControlNetStrength: Schema.number().default(0.7).description('换风格模式的 ControlNet-LLLite 强度,越大构图锁得越死(建议 0.5-0.8;需安装 kohya-ss/ComfyUI-Anima-LLLite 节点与权重)'),
242
242
  i2iIPAdapterPath: Schema.string().default('').description('Anima IP-Adapter 模型文件路径(换装换姿势模式保脸用;需安装 comfyui-anima-ipadapter 节点并把模型路径填到这里)'),
243
243
  i2iIPAdapterWeight: Schema.number().default(0.8).description('换装换姿势模式的 IP-Adapter 权重,越大角色特征保留越强(建议 0.6-1.0)'),
244
- controlNetModel: Schema.string().default('').description('ControlNet 模型文件名(留空自动检测 Qwen/Anima ControlNet;需放到 ComfyUI/models/controlnet)'),
244
+ controlNetModel: Schema.string().default('').description('Anima ControlNet-LLLite 权重文件名(留空自动检测 anima-lllite 系;需放到 ComfyUI/models/controlnet,如 anima-lllite-lineart-test-1.safetensors)'),
245
245
  taggerEnabled: Schema.boolean().default(false).description('i2i 前自动识图(需 ComfyUI 安装 WD14 Tagger 节点与模型;识别出的标签会注入提示词优化)'),
246
246
  taggerModel: Schema.string().default('wd-v1-4-convnext-tagger-v2').description('识图模型名(WD14 Tagger 节点里可选模型)'),
247
247
  taggerThreshold: Schema.number().default(0.35).description('识图标签置信度阈值'),
@@ -566,8 +566,12 @@ function animaI2IWorkflow(cfg, prompt, negativePrompt, width, height, steps, cfg
566
566
  }
567
567
  }
568
568
 
569
- // 「换风格(漫画化)」i2i 工作流:LoadImage → Canny → ControlNetApplyAdvanced 锁构图,
569
+ // 「换风格(漫画化)」i2i 工作流:LoadImage → Canny → AnimaLLLiteApply_sdscripts 锁构图,
570
570
  // VAEEncode 原图作起点,KSampler 用较高 denoise 整体转二次元风格。
571
+ // 注意:Anima 是 MiniTrainDIT 架构(隐藏层 3584 维),与 Qwen-Image 系 ControlNet 不兼容
572
+ // (InstantX 控制网期望 3584 维文本嵌入,Anima 只给 1024 维 → LayerNorm 崩溃)。
573
+ // 因此这里使用 Anima 原生支持的 ControlNet-LLLite(kohya-ss/ComfyUI-Anima-LLLite),
574
+ // 节点直接对 MODEL 打补丁并返回补丁后的模型,交给 KSampler。
571
575
  function animaStyleI2IWorkflow(cfg, prompt, negativePrompt, width, height, steps, cfgVal, seed, inputImage, controlNetModel, controlNetStrength, denoise) {
572
576
  return {
573
577
  '44': { class_type: 'UNETLoader', inputs: { unet_name: cfg.unetName, weight_dtype: 'fp8_e4m3fn' } },
@@ -578,14 +582,13 @@ function animaStyleI2IWorkflow(cfg, prompt, negativePrompt, width, height, steps
578
582
  '11': { class_type: 'CLIPTextEncode', inputs: { text: prompt, clip: ['45', 0] } },
579
583
  '12': { class_type: 'CLIPTextEncode', inputs: { text: negativePrompt, clip: ['45', 0] } },
580
584
  '70': { class_type: 'Canny', inputs: { image: ['13', 0], low_threshold: 0.4, high_threshold: 0.8 } },
581
- '71': { class_type: 'ControlNetLoader', inputs: { control_net_name: controlNetModel } },
582
- '72': { class_type: 'ControlNetApplyAdvanced', inputs: { positive: ['11', 0], negative: ['12', 0], control_net: ['71', 0], image: ['70', 0], strength: controlNetStrength, start_percent: 0, end_percent: 1 } },
585
+ '71': { class_type: 'AnimaLLLiteApply_sdscripts', inputs: { model: ['44', 0], lllite_name: controlNetModel, image: ['70', 0], strength: controlNetStrength, start_percent: 0, end_percent: 1, preserve_wrapper: true } },
583
586
  '19': {
584
587
  class_type: 'KSampler',
585
588
  inputs: {
586
- model: ['44', 0],
587
- positive: ['72', 0],
588
- negative: ['72', 1],
589
+ model: ['71', 0],
590
+ positive: ['11', 0],
591
+ negative: ['12', 0],
589
592
  latent_image: ['30', 0],
590
593
  seed,
591
594
  steps,
@@ -1643,7 +1646,12 @@ exports.apply = async function apply(ctx, cfg) {
1643
1646
 
1644
1647
  const status = history.status || {}
1645
1648
  if (status.status_str && status.status_str !== 'success') {
1646
- return { ok: false, message: `ComfyUI 工作流执行失败:${JSON.stringify(status).slice(0, 400)}` }
1649
+ const execErr = status.messages && status.messages.find((m) => Array.isArray(m) && m[0] === 'execution_error' && m[1])
1650
+ const errData = execErr && execErr[1]
1651
+ const errText = errData
1652
+ ? `[${errData.node_id} ${errData.node_type}] ${errData.exception_type || ''} ${errData.exception_message || ''}`.trim()
1653
+ : ''
1654
+ return { ok: false, message: `ComfyUI 工作流执行失败:${JSON.stringify(status).slice(0, 400)}${errText ? `\n异常:${errText}` : ''}` }
1647
1655
  }
1648
1656
 
1649
1657
  const images = outputImages(history)
@@ -3179,8 +3187,9 @@ exports.apply = async function apply(ctx, cfg) {
3179
3187
  return data.name
3180
3188
  }
3181
3189
 
3182
- // 检测 i2i 可用能力:ControlNet 模型(ControlNetLoader control_net_name 列表)与
3183
- // Anima IP-Adapter 专用节点(comfyui-anima-ipadapter)。检测失败全部视为不可用(回退普通 img2img)。
3190
+ // 检测 i2i 可用能力:Anima ControlNet-LLLite 节点与权重(comfyui-anima-lllite / kohya-ss/ComfyUI-Anima-LLLite)
3191
+ // Anima IP-Adapter 专用节点(comfyui-anima-ipadapter)。检测失败全部视为不可用(回退普通 img2img)。
3192
+ // 注意:Qwen-Image InstantX ControlNet 与 Anima(MiniTrainDIT,3584 维)架构不兼容,这里只认 LLLite 权重。
3184
3193
  async function detectI2ICapabilities() {
3185
3194
  const caps = { controlNet: { available: false, model: null }, ipAdapter: { available: false } }
3186
3195
  let info
@@ -3190,25 +3199,25 @@ exports.apply = async function apply(ctx, cfg) {
3190
3199
  return caps
3191
3200
  }
3192
3201
  if (!info || typeof info !== 'object') return caps
3193
- const cnModels = availableModels(info, 'ControlNetLoader', 'control_net_name')
3194
- if (cnModels.length) {
3195
- caps.controlNet.available = true
3196
- const configured = String(cfg.controlNetModel || '').trim()
3197
- if (configured && cnModels.includes(configured)) {
3198
- caps.controlNet.model = configured
3199
- } else {
3202
+ // Anima ControlNet-LLLite:lllite_name models/controlnet 目录读取,只挑 anima-lllite 系权重
3203
+ if (info.AnimaLLLiteApply_sdscripts) {
3204
+ const llliteModels = availableModels(info, 'AnimaLLLiteApply_sdscripts', 'lllite_name')
3205
+ if (llliteModels.length) {
3206
+ const configured = String(cfg.controlNetModel || '').trim()
3200
3207
  const norm = (s) => String(s).toLowerCase().replace(/[-_ ]/g, '')
3201
- const prefers = ['qwen-image-instantx-controlnet-union', 'anima-instantx-controlnet-union', 'instantx-controlnet-union', 'qwen-image-controlnet-union', 'controlnet-union']
3202
- const pool = cnModels.filter((m) => /qwen|anima|instant|union|canny/i.test(String(m)))
3208
+ const prefers = ['anima-lllite-lineart', 'anima-lllite', 'lllite-lineart', 'lllite']
3209
+ const pool = llliteModels.filter((m) => /lllite/i.test(String(m)))
3203
3210
  const scored = pool.map((m) => ({ m, s: prefers.reduce((acc, p, i) => acc + (norm(m) === norm(p) ? prefers.length - i : 0), 0) }))
3204
3211
  scored.sort((a, b) => b.s - a.s)
3205
- caps.controlNet.model = (scored[0] && scored[0].m) || null
3212
+ const best = (scored[0] && scored[0].m) || null
3213
+ caps.controlNet.model = configured && llliteModels.includes(configured) ? configured : best
3214
+ caps.controlNet.available = !!caps.controlNet.model
3206
3215
  }
3207
3216
  }
3208
3217
  if (info.AnimaIPAdapterLoader && info.AnimaIPAdapterApply && info.AnimaSiglipeEncodeImage) {
3209
3218
  caps.ipAdapter.available = true
3210
3219
  }
3211
- if (cfg.outputLogs) logger.info(`[p-draw] i2i 能力检测:ControlNet=${JSON.stringify(caps.controlNet)} IPAdapter=${JSON.stringify(caps.ipAdapter)}`)
3220
+ if (cfg.outputLogs) logger.info(`[p-draw] i2i 能力检测:ControlNet(LLLite)=${JSON.stringify(caps.controlNet)} IPAdapter=${JSON.stringify(caps.ipAdapter)}`)
3212
3221
  return caps
3213
3222
  }
3214
3223
 
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.2.4",
4
+ "version": "1.2.6",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "index.js",
package/readme.md CHANGED
@@ -14,7 +14,7 @@ p点-绘图插件,连接本地 ComfyUI 生图,参考 AstrBot 的 [anima 绘
14
14
  - 尺寸选择:`竖图` `横图` `方图` `长竖图` `宽屏`,或 `1024x1536:描述` / `--尺寸 1216x832`。
15
15
  - 画师组管理(创建 / 追加 / 切换 / 查看 / 删除)。
16
16
  - 固定角色(`添加角色 名称=tags`)。
17
- - **以图生图**:`p-draw i2i <描述>` 并在同一条消息附一张原图(文件 / 截图 / 链接均可),发送后会让用户选择处理方式(可用 `i2iMode` 固定跳过询问):**① 换风格(漫画化)**——保留原图构图,整体转成二次元画风,优先用 ControlNetCanny 锁构图);**② 换装换姿势**——保留角色长相,重新设计服装 / 姿势 / 场景,优先用 Anima IP-Adapter(保脸);**③ 取消**——不生成。支持 `--denoise 0.6` / `--去噪 0.4` 单独调整强度;未安装对应节点 / 模型时自动回退普通 img2img(纯 `LoadImage → VAEEncode → KSampler(denoise<1)`,**无需修改 ComfyUI**),去噪强度由 `img2imgDenoise` 控制(默认 0.55)。不支持自定义工作流(`customWorkflowEnabled`)时使用 i2i 会提示关闭。
17
+ - **以图生图**:`p-draw i2i <描述>` 并在同一条消息附一张原图(文件 / 截图 / 链接均可),发送后会让用户选择处理方式(可用 `i2iMode` 固定跳过询问):**① 换风格(漫画化)**——保留原图构图,整体转成二次元画风,优先用 Anima **ControlNet-LLLite**(Canny 锁构图);**② 换装换姿势**——保留角色长相,重新设计服装 / 姿势 / 场景,优先用 Anima IP-Adapter(保脸);**③ 取消**——不生成。支持 `--denoise 0.6` / `--去噪 0.4` 单独调整强度;未安装对应节点 / 模型时自动回退普通 img2img(纯 `LoadImage → VAEEncode → KSampler(denoise<1)`,**无需修改 ComfyUI**),去噪强度由 `img2imgDenoise` 控制(默认 0.55)。不支持自定义工作流(`customWorkflowEnabled`)时使用 i2i 会提示关闭。
18
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`)且非 `无优化` 模式时才会识图;识图失败会跳过并正常生图。
19
19
  - **用户自选模型**:`p-draw 模型` 查看当前与可用模型(自动读取 ComfyUI 的 UNET 列表),`p-draw 模型 <名称>` 切换(支持模糊匹配,如 `anima-aesthetic`),`p-draw 模型 默认` 恢复默认。偏好按用户保存(`p_draw_config.user_models`),单人 / 多人 / 连续图都生效;未自选时用 `unetName` 默认模型。自定义工作流(`customWorkflowEnabled`)不参与模型切换。
20
20
  - 画师组与固定角色**保存在数据库 `p_draw_config` 表中**,管理指令不触发插件重载(不会打断正在生成的图,也不会把配置恢复成默认)。数据库中的值在重启后覆盖配置里的同名项。
@@ -81,8 +81,8 @@ plugins:
81
81
  | `i2iAskTimeout` | i2i 处理方式询问等待时间(秒,默认 60) |
82
82
  | `i2iStyleDenoise` | 换风格(漫画化)去噪强度,默认 0.75(建议 0.7-0.85,越大风格变化越彻底;无 ControlNet 时自动压到 0.5 防崩) |
83
83
  | `i2iOotdDenoise` | 换装换姿势去噪强度,默认 0.55(建议 0.5-0.6) |
84
- | `i2iControlNetStrength` | 换风格模式的 ControlNet 强度,默认 0.7(建议 0.5-0.8,越大构图锁得越死) |
85
- | `controlNetModel` | ControlNet 模型文件名(留空自动检测 Qwen/Anima 系,如 `Qwen-Image-InstantX-ControlNet-Union.safetensors`;需放到 ComfyUI `models/controlnet/`) |
84
+ | `i2iControlNetStrength` | 换风格模式的 ControlNet-LLLite 强度,默认 0.7(建议 0.5-0.8,越大构图锁得越死) |
85
+ | `controlNetModel` | Anima ControlNet-LLLite 权重文件名(留空自动检测 `anima-lllite` 系,如 `anima-lllite-lineart-test-1.safetensors`;需放到 ComfyUI `models/controlnet/`) |
86
86
  | `i2iIPAdapterPath` | Anima IP-Adapter 模型文件**路径**(换装换姿势保脸用,如 `E:/anima/ipadapter.safetensors`;需安装 [comfyui-anima-ipadapter](https://github.com/Wenaka2004/comfyui-anima-ipadapter) 节点) |
87
87
  | `i2iIPAdapterWeight` | 换装换姿势模式的 IP-Adapter 权重,默认 0.8(建议 0.6-1.0,越大角色特征保留越强) |
88
88
  | `taggerEnabled` / `taggerModel` / `taggerThreshold` / `taggerCharacterThreshold` | i2i 自动识图开关、识图模型名、标签阈值 / 角色标签阈值(需 ComfyUI 安装 WD14 Tagger 节点与模型) |
@@ -111,5 +111,5 @@ plugins:
111
111
  - 券为一次性、**按张数消耗**:`x3` 需 3 张,每张图独立做一次 LLM 优化;券不足时该批不优化也不扣券(提示 `token-short`)。等待回复时间由 `couponAskTimeout`(秒)控制。
112
112
  - **管理员在全局关闭时自动免费优化**(不耗券);`无优化` 原样模式不消耗、不询问。平台不支持交互确认时退回自动消耗逻辑。
113
113
  - **未使用优化的提示**:单人生图没走 LLM 优化时会明确提示原因——未配置 LLM、未消耗优化券、或 `无优化` 原样模式;多人指令强依赖 LLM 规划,未配置 `llmBaseUrl`/`llmModel` 时会直接提示「多人指令需要 LLM 规划」。
114
- - **i2i 增强模式依赖的节点**:换风格(漫画化)需要 ComfyUI `models/controlnet/` 里有 Qwen/Anima 系 ControlNet 模型(`ControlNetLoader` 下拉可见);换装换姿势需要安装 [comfyui-anima-ipadapter](https://github.com/Wenaka2004/comfyui-anima-ipadapter) 自定义节点并配置 `i2iIPAdapterPath`。两者缺失时都会自动回退普通 img2img 并提示,不影响出图。
114
+ - **i2i 增强模式依赖的节点**:换风格(漫画化)需要 ComfyUI 安装 [kohya-ss/ComfyUI-Anima-LLLite](https://github.com/kohya-ss/ComfyUI-Anima-LLLite) 自定义节点,并在 `models/controlnet/` 放一个 `anima-lllite` 系权重(`AnimaLLLiteApply_sdscripts` 节点下拉可见)。**注意:Anima 是 MiniTrainDIT 架构(3584 维),与 Qwen-Image 系 ControlNet(如 `Qwen-Image-InstantX-ControlNet-Union`)不兼容,装了也不会被本插件使用。** 换装换姿势需要安装 [comfyui-anima-ipadapter](https://github.com/Wenaka2004/comfyui-anima-ipadapter) 自定义节点并配置 `i2iIPAdapterPath`。两者缺失时都会自动回退普通 img2img 并提示,不影响出图。
115
115
  - 本地模型不一定认识新角色,可用 `添加角色` 手动补充角色 tags。