提示词预设pro
This commit is contained in:
+56
-17
@@ -53,7 +53,7 @@ const XBR_INFERENCE_MODES_ = XBR_INFERENCE_MODES;
|
||||
function xbrLlmDefaults() {
|
||||
return {
|
||||
model: { model: "", mmproj: "None", chat_handler: "None", n_ctx: 8192, vram_limit: -1, image_min_tokens: 0, image_max_tokens: 0 },
|
||||
run: { inference_mode: "one by one", max_frames: 24, max_size: 256, seed: 0, seed_control: "randomize", force_offload: false, save_states: false },
|
||||
run: { inference_mode: "one by one", max_frames: 24, max_size: 256, seed: 0, seed_control: "randomize", force_offload: false, save_states: false, strip_thinking: true },
|
||||
params: {
|
||||
max_tokens: 6144, top_k: 40, top_p: 0.9, min_p: 0.05, typical_p: 1.0, temperature: 0.6,
|
||||
repeat_penalty: 1.12, frequency_penalty: 0.0, present_penalty: 0.0,
|
||||
@@ -83,6 +83,7 @@ function xbrParseLlm(raw) {
|
||||
cfg.run.seed_control = xbrPick(r.seed_control, XBR_SEED_MODES, cfg.run.seed_control);
|
||||
cfg.run.force_offload = xbrFlag(r.force_offload, cfg.run.force_offload);
|
||||
cfg.run.save_states = xbrFlag(r.save_states, cfg.run.save_states);
|
||||
cfg.run.strip_thinking = xbrFlag(r.strip_thinking, cfg.run.strip_thinking); // 模型输出思考过程时自动过滤
|
||||
|
||||
const p = (d.params && typeof d.params === "object") ? d.params : {};
|
||||
cfg.params.max_tokens = xbrInt(p.max_tokens, cfg.params.max_tokens, 0, 262144);
|
||||
@@ -131,7 +132,7 @@ function xbrSaveJson(node, patch) {
|
||||
return cur;
|
||||
}
|
||||
|
||||
/* ── 预设设定词(三视图 / 四视图 / 背景纯透明的设定文本)─────────────
|
||||
/* ── 预设设定词(三视图 / 四视图 / 五视图 / 背景纯透明的设定文本)─────────────
|
||||
* · 用户改过的按「模式|语言」存进节点(基础面板的 preset_texts 存档);
|
||||
* · 弹窗读「存档 → 默认」,提交时同步写 widget + 存档。 */
|
||||
function xbrPresetStore(node) {
|
||||
@@ -142,6 +143,28 @@ function xbrPresetTextFor(node, mode, lang) {
|
||||
return (t && String(t).trim()) ? t : (defaultPresetOf(mode, lang) || "");
|
||||
}
|
||||
|
||||
/* ── 预设选项按「输出语言」过滤 ───────────────────────────────
|
||||
* 预设名的语言标签形如 "Z-Image Turbo [ZH]" / "Normal - 描述 [EN]";
|
||||
* 输出语言选中文 → 增强预设 / 反推预设 只列 [ZH] 项,选英文 → 只列 [EN] 项。 */
|
||||
function xbrLangTagOf(v) {
|
||||
const m = String(v == null ? "" : v).match(/[\[[](ZH|EN)[\]]]\s*$/i);
|
||||
return m ? m[1].toUpperCase() : "";
|
||||
}
|
||||
function xbrFilterByLang(opts, lang) {
|
||||
const want = xbrLangTagOf(lang);
|
||||
if (!want) return opts.slice();
|
||||
const hit = opts.filter((o) => xbrLangTagOf(o) === want);
|
||||
return hit.length ? hit : opts.slice(); // 全无语言标签(老预设)→ 全量兜底
|
||||
}
|
||||
/** 语言变了:优先换到「同名的另一语言项」,否则取该语言第一项 */
|
||||
function xbrSnapPreset(opts, cur, lang) {
|
||||
const list = xbrFilterByLang(opts, lang);
|
||||
if (list.includes(cur)) return cur;
|
||||
const base = String(cur == null ? "" : cur).replace(/\s*[\[[](ZH|EN)[\]]]\s*$/i, "").trim();
|
||||
const same = list.find((o) => String(o).replace(/\s*[\[[](ZH|EN)[\]]]\s*$/i, "").trim() === base);
|
||||
return same || list[0] || cur;
|
||||
}
|
||||
|
||||
/* ── 在线 API(存 ComfyUI user 目录,Key 不进工作流)──────── */
|
||||
async function xbrApiGet() {
|
||||
const resp = await api.fetchApi(XBR_API_ENDPOINT);
|
||||
@@ -338,8 +361,11 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
draft.lang = v;
|
||||
// 换语言 → 未在弹窗里改过设定词时,跟着取该语言的「存档 → 默认」
|
||||
if (!draft.presetTouched) draft.presetText = xbrPresetTextFor(node, draft.mode, v);
|
||||
// 语言决定预设可选范围:增强预设 / 反推预设 自动换到同语言的同名项(没有则取该语言第一项)
|
||||
draft.preset = xbrSnapPreset(xbrWidgetOptions(node, "preset"), draft.preset, v);
|
||||
draft.task_preset = xbrSnapPreset(xbrWidgetOptions(node, "task_preset"), draft.task_preset, v);
|
||||
})));
|
||||
body.append(xbrHint("本项是唯一的语言设置:① 元素词表 / 预设句按哪种语言加载 ② LLM 反推最终输出的提示词是中文还是英文。其他地方不再有语言选项。"));
|
||||
body.append(xbrHint("本项是唯一的语言设置:① 词表 / 设定词 / 预设句按哪种语言加载 ② 增强预设与反推预设只列该语言的选项 ③ 最终输出的提示词语言。"));
|
||||
|
||||
body.append(makeSectionTitle("提示词增强反推(总开关在节点表面的「启用 LLM 反推」)"));
|
||||
|
||||
@@ -352,7 +378,7 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
const llm = s.model;
|
||||
const models = lists.model.length ? lists.model : (llm.model ? [llm.model] : []);
|
||||
if (!llm.model && models.length) llm.model = models[0];
|
||||
body.append(field("强制卸载", checkboxControl(s.run.force_offload, "LLM 用完即卸载(释放显存)", (v) => { s.run.force_offload = v; })));
|
||||
body.append(field("强制卸载", checkboxControl(s.run.force_offload, "LLM 用完即卸载,释放显存", (v) => { s.run.force_offload = v; })));
|
||||
if (models.length) body.append(field("模型", selectControl(models, llm.model, (v) => { llm.model = v; })));
|
||||
else body.append(field("模型", xbrTextControl(llm.model, "未找到本地 LLM 模型(.gguf 放到 models/LLM)", (v) => { llm.model = v; })));
|
||||
body.append(field("视觉模块 mmproj", selectControl(lists.mmproj.length ? lists.mmproj : ["None"], llm.mmproj, (v) => { llm.mmproj = v; })));
|
||||
@@ -382,7 +408,7 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
const a = draft.api || (draft.api = { ...XBR_API_DEFAULTS });
|
||||
body.append(field("服务商", selectControl(ctx.providers, a.provider, (v) => { a.provider = v; })));
|
||||
body.append(field("模型", xbrTextControl(a.model, XBR_API_DEFAULTS.model, (v) => { a.model = v; })));
|
||||
body.append(field("API Key", xbrPasswordControl(a.api_key, "sk-…(保存在本地,不写入工作流)", (v) => { a.api_key = v; })));
|
||||
body.append(field("API Key", xbrPasswordControl(a.api_key, "sk-… 保存在本地,不写入工作流", (v) => { a.api_key = v; })));
|
||||
body.append(field("Base URL", xbrTextControl(a.base_url, XBR_API_DEFAULTS.base_url, (v) => { a.base_url = v; })));
|
||||
body.append(field("temperature", xbrNumberControl(a.temperature, { min: 0, max: 2, step: 0.01 }, (v) => { a.temperature = v; })));
|
||||
body.append(field("max_tokens", xbrNumberControl(a.max_tokens, { min: 1, max: 262144, step: 1 }, (v) => { a.max_tokens = Math.round(v); })));
|
||||
@@ -398,8 +424,13 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
body.append(field("推理模式", selectControl(XBR_INFERENCE_MODES, s.run.inference_mode, (v) => { s.run.inference_mode = v; })));
|
||||
body.append(field("最大帧数", xbrNumberControl(s.run.max_frames, { min: 2, max: 1024, step: 1 }, (v) => { s.run.max_frames = Math.round(v); })));
|
||||
body.append(field("最大尺寸", xbrNumberControl(s.run.max_size, { min: 128, max: 16384, step: 64 }, (v) => { s.run.max_size = Math.round(v); })));
|
||||
body.append(field("保存对话状态", checkboxControl(s.run.save_states, "在内存中保留本次对话上下文(多轮连续反推)", (v) => { s.run.save_states = v; })));
|
||||
body.append(field("保存对话状态", checkboxControl(s.run.save_states, "在内存中保留本次对话上下文,多轮连续反推", (v) => { s.run.save_states = v; })));
|
||||
body.append(field("状态 UID", xbrNumberControl(s.params.state_uid, { min: -1, max: 999999, step: 1 }, (v) => { s.params.state_uid = Math.round(v); })));
|
||||
body.append(field("🧠 过滤思考过程", checkboxControl(s.run.strip_thinking,
|
||||
"模型把「思考过程 / 推理段 / 工作流程」一起输出时,自动只保留最终提示词", (v) => { s.run.strip_thinking = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.65;margin:2px 0 8px;",
|
||||
"开启后=① 系统提示词末尾追加「只输出最终提示词」硬规则 ② 仍漏出思考时自动剔除思考标签、"
|
||||
+ "Final Output / 最终输出 标记之前的推理段与代码围栏(拿不到内容则原文保留)。"));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "提示词正文在节点上的提示词框里编辑;「📝 提示词」端口接线后该框锁定。"));
|
||||
}
|
||||
|
||||
@@ -417,7 +448,7 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
draft.presetText = xbrPresetTextFor(node, v, draft.lang);
|
||||
ctx.rerender(); // 有/无设定词的模式之间切换 → 重画「设定词」区
|
||||
})));
|
||||
body.append(xbrHint("常规文生图 = 只输出正文;人物三视图 / 人物四视图 / 背景纯透明 = 最终提示词最顶端自动加上该模式的设定词。"));
|
||||
body.append(xbrHint("常规文生图 = 只输出正文;人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 = 最终提示词最顶端自动加上该模式的设定词。"));
|
||||
|
||||
// ── 设定词(预设模式对应的设定文本;只在弹窗里编辑,节点表面不显示)──
|
||||
const modeDef = defaultPresetOf(draft.mode, draft.lang);
|
||||
@@ -426,7 +457,7 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
if (!String(draft.presetText || "").trim()) draft.presetText = modeDef;
|
||||
const taP = textareaControl(draft.presetText, (v) => { draft.presetText = v; draft.presetTouched = true; },
|
||||
"width:100%;box-sizing:border-box;min-height:180px;resize:vertical;");
|
||||
taP.placeholder = "该模式的设定词(改过的按「模式 + 语言」记进节点,换模式 / 换语言都不丢)";
|
||||
taP.placeholder = "该模式的设定词;改过的按「模式 + 语言」记进节点,换模式 / 换语言都不丢";
|
||||
taP.spellcheck = false;
|
||||
body.append(taP);
|
||||
const taRow = el("div", "display:flex;align-items:center;gap:10px;margin:6px 0 4px;");
|
||||
@@ -445,19 +476,20 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
}
|
||||
|
||||
body.append(makeSectionTitle("增强预设(= 提示词设定 / system prompt)"));
|
||||
const presetOpts = xbrWidgetOptions(node, "preset");
|
||||
const presetOpts = xbrFilterByLang(xbrWidgetOptions(node, "preset"), draft.lang);
|
||||
if (presetOpts.length) body.append(field("增强预设", selectControl(presetOpts, draft.preset, (v) => { draft.preset = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "该预设内容即「🧩 提示词设定」输出的正文,同时作为 LLM 反推的系统提示词。"));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;",
|
||||
`该预设内容即「🧩 提示词设定」输出的正文,同时作为 LLM 反推的系统提示词;只列与输出语言 ${draft.lang} 相符的预设。`));
|
||||
|
||||
body.append(makeSectionTitle("反推预设"));
|
||||
const taskOpts = xbrWidgetOptions(node, "task_preset");
|
||||
const taskOpts = xbrFilterByLang(xbrWidgetOptions(node, "task_preset"), draft.lang);
|
||||
if (taskOpts.length) body.append(field("反推预设", selectControl(taskOpts, draft.task_preset, (v) => { draft.task_preset = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "带 * 的预设里 * 是必填占位符,由节点上的提示词框或外接「📝 提示词」填入。"));
|
||||
|
||||
body.append(makeSectionTitle("追加设定(可留空)"));
|
||||
const ta = textareaControl(s.extra_system, (v) => { s.extra_system = v; },
|
||||
"width:100%;box-sizing:border-box;min-height:200px;resize:vertical;");
|
||||
ta.placeholder = "追加在增强预设之后的额外要求(例:只输出一行、不要解释过程…)";
|
||||
ta.placeholder = "追加在增强预设之后的额外要求,例:只输出一行、不要解释过程…";
|
||||
ta.spellcheck = false;
|
||||
body.append(ta);
|
||||
}
|
||||
@@ -472,22 +504,26 @@ function xbrRenderHelp(body) {
|
||||
" · 🖼️ 图像:外接图像 / 视频帧(LLM 反推:图 → 提示词)",
|
||||
"",
|
||||
"【输出端口】",
|
||||
" · 📝 提示词:最终提示词(未启用 LLM = 拼装好的提示词;启用 LLM = 设定词原样置顶 + LLM 增强后的正文)",
|
||||
" · 📝 提示词:最终提示词。未启用 LLM = 拼装好的提示词;启用 LLM = 设定词原封不动置顶 + LLM 增强后的正文",
|
||||
" · 🖼️ 空latent:第二位。按「空latent类型」生成,官方 latent_format 逐字段对齐",
|
||||
" · 📋 提示词列表:按行拆分",
|
||||
" · 🧩 提示词设定:本次的提示词设定(增强预设 + 输出语言 + 追加设定)",
|
||||
" · 🖼️ 空latent:按「空latent类型」生成(官方 latent_format 逐字段对齐)",
|
||||
" · 🧩 提示词设定:本次的提示词设定,即增强预设 + 输出语言 + 追加设定",
|
||||
"",
|
||||
"【节点表面】",
|
||||
" · 第 1 行按钮:🤖 LLM设置(唯一语言设置 / 后端 / 采样参数)| ✨ 增强预设(空latent类型 / 预设模式 / 增强预设 / 反推预设 / 追加设定)| 📖 使用说明",
|
||||
" · 第 2 行按钮:8 个元素分类(点选项行加入/移除提示词,【添加详细描述】写补充说明)",
|
||||
" · ✅ 启用 LLM 反推:关(默认)= 原「生图提示词预设」行为;开 = 图/文 → 提示词",
|
||||
" · 设定词:预设模式(三视图 / 四视图 / 背景纯透明)的设定文本,在「✨ 增强预设」弹窗里编辑;"
|
||||
" · 设定词:预设模式(三视图 / 四视图 / 五视图 / 背景纯透明)的设定文本,在「✨ 增强预设」弹窗里编辑;"
|
||||
+ "改过的随节点保存,换模式 / 换语言不丢;输出时原封不动加在增强结果的顶端,也作为 LLM 的增强参考",
|
||||
" · 提示词框右上角「📋 复制」;下方「参数设定显示」实时显示当前配置",
|
||||
"",
|
||||
"【保存】",
|
||||
" · 弹窗底部:☑ 自动保存(默认开)+ 字号 + 界面缩放;「取消」丢弃未保存改动",
|
||||
" · 配置随工作流保存;在线 API 的 Key 存在 ComfyUI user 目录,不进工作流",
|
||||
"",
|
||||
"【语言 / 思考过程】",
|
||||
" · 输出语言(🤖 LLM设置)是唯一语言设置:决定词表与设定词按哪种语言加载、增强预设与反推预设只列哪种语言的选项、最终提示词的语言",
|
||||
" · 🧠 过滤思考过程(🤖 LLM设置 → 指令推理,默认开):系统提示词末尾追加「只输出最终提示词」硬规则;模型仍漏出思考过程时,自动剔掉思考标签、Final Output / 最终输出 之前的推理段与代码围栏",
|
||||
];
|
||||
body.append(el("div", "font-size:12px;color:#bbb;line-height:1.9;white-space:pre-wrap;font-family:ui-monospace,Consolas,monospace;", lines.join("\n")));
|
||||
}
|
||||
@@ -507,10 +543,13 @@ async function xbrOpenModal(node, panelId) {
|
||||
lang: xbrPick(String(xbrWidgetVal(node, "output_lang") ?? ""), LANGS, LANGS[0]),
|
||||
kind: xbrPick(String(xbrWidgetVal(node, "latent_kind") ?? ""), LATENT_KINDS, LATENT_KINDS[0]),
|
||||
mode: xbrPick(String(xbrWidgetVal(node, "preset_mode") ?? ""), MODES, MODES[0]),
|
||||
// 设定词(三视图/四视图/背景纯透明):弹窗内草稿 + 「用户是否改过」标记
|
||||
// 设定词(三视图/四视图/五视图/背景纯透明):弹窗内草稿 + 「用户是否改过」标记
|
||||
presetText: String(xbrWidgetVal(node, "three_view_text") ?? ""),
|
||||
presetTouched: false,
|
||||
};
|
||||
// 预设选项与输出语言对齐(旧工作流可能存着异语言的预设名)
|
||||
draft.preset = xbrSnapPreset(xbrWidgetOptions(node, "preset"), draft.preset, draft.lang);
|
||||
draft.task_preset = xbrSnapPreset(xbrWidgetOptions(node, "task_preset"), draft.task_preset, draft.lang);
|
||||
|
||||
let apiSaved = null, providers = [XBR_DEFAULT_PROVIDER];
|
||||
if (panelId === "llm") {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* XB-BOX - 🖼️ 生图提示词预设 — 前端面板
|
||||
* ============================================================
|
||||
* 节点:XB_ImagePromptPreset(后端 nodes_image_prompt_preset.py,V1 经典 API)
|
||||
* 表面:空latent类型 / 输出语言 / 预设模式 / (三视图预设句)/ 画幅比例 / 宽度 / 高度 / 生成数量
|
||||
* 表面:空latent类型 / 输出语言 / 预设模式 / (三视图/四视图/五视图预设句)/ 画幅比例 / 宽度 / 高度 / 生成数量
|
||||
* + 节点提示词框 + 8 个分类按钮(4 列 × 2 行):🏷️ 风格 | 🎥 视角 | 👤 主体 | 🎬 姿态 | 👚 装扮 | 🎒 道具 | 💡 光影 | 🏞️ 背景
|
||||
* 每个按钮一个面板,面板顶部「分类签」切子类;选项行整行可点(加入 → 变蓝 ✔ / 再点移除)
|
||||
* 道具类点行会先弹「与主体的关系」多宫格标签窗(30 个关系词)
|
||||
@@ -32,8 +32,9 @@ const LANGS = [LANG_ZH, LANG_EN];
|
||||
const MODE_TP = "常规文生图";
|
||||
const MODE_3V = "人物三视图";
|
||||
const MODE_4V = "人物四视图";
|
||||
const MODE_5V = "人物五视图";
|
||||
const MODE_RGBA = "背景纯透明";
|
||||
const MODES = [MODE_TP, MODE_3V, MODE_4V, MODE_RGBA];
|
||||
const MODES = [MODE_TP, MODE_3V, MODE_4V, MODE_5V, MODE_RGBA];
|
||||
|
||||
const ASPECT_MAP = { "1:1": 1, "16:9": 16 / 9, "9:16": 9 / 16, "4:3": 4 / 3, "3:4": 3 / 4, "21:9": 21 / 9 };
|
||||
const SIZE_STEP = 16; // width/height 的兜底步长(实际以「空latent类型」的官方最小步长为准)
|
||||
@@ -71,6 +72,10 @@ const PRESET_TEXT_DEFAULT = {
|
||||
[LANG_ZH]: "生成四宫格排列的角色概念设计图,画面左上角面板是角色面部的精细特写肖像,画面右上角面板是角色面部侧面的的精细特写肖像,画面左下角面板是无头部人物正面衣着展示图,画面右下角面板是人物背面全身站姿。",
|
||||
[LANG_EN]: "Generate a character concept design sheet arranged in a 2x2 grid, the top-left panel is a finely detailed close-up portrait of the character's face, the top-right panel is a finely detailed close-up profile portrait of the character's face, the bottom-left panel is a headless front-facing outfit display view, the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
[MODE_5V]: {
|
||||
[LANG_ZH]: "生成五宫格排列的角色概念设计图,画面左上角面板是角色面部的精细特写肖像,画面右上角面板是角色面部侧面的的精细特写肖像,画面下方左侧面板是无头部人物正面衣着展示图,画面下方中间面板是无头部人物侧面衣着展示图,画面下方右侧面板是人物背面全身站姿。",
|
||||
[LANG_EN]: "Generate a character concept design sheet arranged in five panels, the top-left panel is a finely detailed close-up portrait of the character's face, the top-right panel is a finely detailed close-up profile portrait of the character's face, the bottom-left panel is a headless front-facing outfit display view, the bottom-middle panel is a headless side-facing outfit display view, the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
[MODE_RGBA]: {
|
||||
[LANG_ZH]: "生成一张具有透明度的 RGBA 格式图像,包含 Alpha 通道,背景为纯透明。",
|
||||
[LANG_EN]: "Generate an RGBA image with an alpha channel and a fully transparent background.",
|
||||
@@ -83,7 +88,7 @@ const THREE_VIEW_DEFAULT = PRESET_TEXT_DEFAULT[MODE_3V];
|
||||
|
||||
/**
|
||||
* ── 预设句(设定词)档案 ─────────────────────────────────────────────
|
||||
* 需求:预设模式(三视图 / 四视图 / 背景纯透明)的设定词可编辑,且**改过就存进节点、
|
||||
* 需求:预设模式(三视图 / 四视图 / 五视图 / 背景纯透明)的设定词可编辑,且**改过就存进节点、
|
||||
* 换模式 / 换语言都不丢**(切换时取「存档 → 默认」,绝不把用户改过的冲掉)。
|
||||
* 存档位置 = manager_settings.preset_texts(JSON 字符串随工作流一起保存):
|
||||
* { "人物三视图|中文 [ZH]": "用户改过的设定词", … } ← 只存与默认不同的那条
|
||||
@@ -2677,7 +2682,7 @@ function setupNode(node) {
|
||||
try { node.setDirtyCanvas?.(true, true); } catch (_) {}
|
||||
};
|
||||
|
||||
// 预设句输入框:常规文生图以外的 3 个模式(三视图/四视图/背景纯透明)都显示(一次性隐藏/显示,不做任何 setSize,不会抖动)
|
||||
// 预设句输入框:常规文生图以外的 4 个模式(三视图/四视图/五视图/背景纯透明)都显示(一次性隐藏/显示,不做任何 setSize,不会抖动)
|
||||
const applyPresetTextVisibility = () => {
|
||||
try {
|
||||
if (PRESET_TEXT_DEFAULT[surfaceOf().mode]) { showWidget(w3v); stylePresetTextBox(); } else hideWidget(w3v);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* XB-BOX - 🖼️ 生图提示词预设 — 前端面板
|
||||
* ============================================================
|
||||
* 节点:XB_ImagePromptPreset(后端 nodes_image_prompt_preset.py,V1 经典 API)
|
||||
* 表面:空latent类型 / 输出语言 / 预设模式 / (三视图预设句)/ 画幅比例 / 宽度 / 高度 / 生成数量
|
||||
* 表面:空latent类型 / 输出语言 / 预设模式 / (三视图/四视图/五视图预设句)/ 画幅比例 / 宽度 / 高度 / 生成数量
|
||||
* + 节点提示词框 + 8 个分类按钮(4 列 × 2 行):🏷️ 风格 | 🎥 视角 | 👤 主体 | 🎬 姿态 | 👚 装扮 | 🎒 道具 | 💡 光影 | 🏞️ 背景
|
||||
* 每个按钮一个面板,面板顶部「分类签」切子类;选项行整行可点(加入 → 变蓝 ✔ / 再点移除)
|
||||
* 道具类点行会先弹「与主体的关系」多宫格标签窗(30 个关系词)
|
||||
@@ -33,8 +33,9 @@ const LANGS = [LANG_ZH, LANG_EN];
|
||||
const MODE_TP = "常规文生图";
|
||||
const MODE_3V = "人物三视图";
|
||||
const MODE_4V = "人物四视图";
|
||||
const MODE_5V = "人物五视图";
|
||||
const MODE_RGBA = "背景纯透明";
|
||||
const MODES = [MODE_TP, MODE_3V, MODE_4V, MODE_RGBA];
|
||||
const MODES = [MODE_TP, MODE_3V, MODE_4V, MODE_5V, MODE_RGBA];
|
||||
|
||||
const ASPECT_MAP = { "1:1": 1, "16:9": 16 / 9, "9:16": 9 / 16, "4:3": 4 / 3, "3:4": 3 / 4, "21:9": 21 / 9 };
|
||||
const SIZE_STEP = 16; // width/height 的兜底步长(实际以「空latent类型」的官方最小步长为准)
|
||||
@@ -72,6 +73,10 @@ const PRESET_TEXT_DEFAULT = {
|
||||
[LANG_ZH]: "生成四宫格排列的角色概念设计图,画面左上角面板是角色面部的精细特写肖像,画面右上角面板是角色面部侧面的的精细特写肖像,画面左下角面板是无头部人物正面衣着展示图,画面右下角面板是人物背面全身站姿。",
|
||||
[LANG_EN]: "Generate a character concept design sheet arranged in a 2x2 grid, the top-left panel is a finely detailed close-up portrait of the character's face, the top-right panel is a finely detailed close-up profile portrait of the character's face, the bottom-left panel is a headless front-facing outfit display view, the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
[MODE_5V]: {
|
||||
[LANG_ZH]: "生成五宫格排列的角色概念设计图,画面左上角面板是角色面部的精细特写肖像,画面右上角面板是角色面部侧面的的精细特写肖像,画面下方左侧面板是无头部人物正面衣着展示图,画面下方中间面板是无头部人物侧面衣着展示图,画面下方右侧面板是人物背面全身站姿。",
|
||||
[LANG_EN]: "Generate a character concept design sheet arranged in five panels, the top-left panel is a finely detailed close-up portrait of the character's face, the top-right panel is a finely detailed close-up profile portrait of the character's face, the bottom-left panel is a headless front-facing outfit display view, the bottom-middle panel is a headless side-facing outfit display view, the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
[MODE_RGBA]: {
|
||||
[LANG_ZH]: "生成一张具有透明度的 RGBA 格式图像,包含 Alpha 通道,背景为纯透明。",
|
||||
[LANG_EN]: "Generate an RGBA image with an alpha channel and a fully transparent background.",
|
||||
@@ -84,7 +89,7 @@ const THREE_VIEW_DEFAULT = PRESET_TEXT_DEFAULT[MODE_3V];
|
||||
|
||||
/**
|
||||
* ── 预设句(设定词)档案 ─────────────────────────────────────────────
|
||||
* 需求:预设模式(三视图 / 四视图 / 背景纯透明)的设定词可编辑,且**改过就存进节点、
|
||||
* 需求:预设模式(三视图 / 四视图 / 五视图 / 背景纯透明)的设定词可编辑,且**改过就存进节点、
|
||||
* 换模式 / 换语言都不丢**(切换时取「存档 → 默认」,绝不把用户改过的冲掉)。
|
||||
* 存档位置 = manager_settings.preset_texts(JSON 字符串随工作流一起保存):
|
||||
* { "人物三视图|中文 [ZH]": "用户改过的设定词", … } ← 只存与默认不同的那条
|
||||
@@ -2693,7 +2698,7 @@ function setupNode(node) {
|
||||
try { node.setDirtyCanvas?.(true, true); } catch (_) {}
|
||||
};
|
||||
|
||||
// 预设句输入框:常规文生图以外的 3 个模式(三视图/四视图/背景纯透明)都显示(一次性隐藏/显示,不做任何 setSize,不会抖动)
|
||||
// 预设句输入框:常规文生图以外的 4 个模式(三视图/四视图/五视图/背景纯透明)都显示(一次性隐藏/显示,不做任何 setSize,不会抖动)
|
||||
const applyPresetTextVisibility = () => {
|
||||
try {
|
||||
// Pro:设定词只在「✨ 增强预设」弹窗里编辑 → 节点表面始终隐藏(不把选项参数暴露在外面)
|
||||
@@ -3057,7 +3062,7 @@ const XBR_INFERENCE_MODES_ = XBR_INFERENCE_MODES;
|
||||
function xbrLlmDefaults() {
|
||||
return {
|
||||
model: { model: "", mmproj: "None", chat_handler: "None", n_ctx: 8192, vram_limit: -1, image_min_tokens: 0, image_max_tokens: 0 },
|
||||
run: { inference_mode: "one by one", max_frames: 24, max_size: 256, seed: 0, seed_control: "randomize", force_offload: false, save_states: false },
|
||||
run: { inference_mode: "one by one", max_frames: 24, max_size: 256, seed: 0, seed_control: "randomize", force_offload: false, save_states: false, strip_thinking: true },
|
||||
params: {
|
||||
max_tokens: 6144, top_k: 40, top_p: 0.9, min_p: 0.05, typical_p: 1.0, temperature: 0.6,
|
||||
repeat_penalty: 1.12, frequency_penalty: 0.0, present_penalty: 0.0,
|
||||
@@ -3087,6 +3092,7 @@ function xbrParseLlm(raw) {
|
||||
cfg.run.seed_control = xbrPick(r.seed_control, XBR_SEED_MODES, cfg.run.seed_control);
|
||||
cfg.run.force_offload = xbrFlag(r.force_offload, cfg.run.force_offload);
|
||||
cfg.run.save_states = xbrFlag(r.save_states, cfg.run.save_states);
|
||||
cfg.run.strip_thinking = xbrFlag(r.strip_thinking, cfg.run.strip_thinking); // 模型输出思考过程时自动过滤
|
||||
|
||||
const p = (d.params && typeof d.params === "object") ? d.params : {};
|
||||
cfg.params.max_tokens = xbrInt(p.max_tokens, cfg.params.max_tokens, 0, 262144);
|
||||
@@ -3135,7 +3141,7 @@ function xbrSaveJson(node, patch) {
|
||||
return cur;
|
||||
}
|
||||
|
||||
/* ── 预设设定词(三视图 / 四视图 / 背景纯透明的设定文本)─────────────
|
||||
/* ── 预设设定词(三视图 / 四视图 / 五视图 / 背景纯透明的设定文本)─────────────
|
||||
* · 用户改过的按「模式|语言」存进节点(基础面板的 preset_texts 存档);
|
||||
* · 弹窗读「存档 → 默认」,提交时同步写 widget + 存档。 */
|
||||
function xbrPresetStore(node) {
|
||||
@@ -3146,6 +3152,28 @@ function xbrPresetTextFor(node, mode, lang) {
|
||||
return (t && String(t).trim()) ? t : (defaultPresetOf(mode, lang) || "");
|
||||
}
|
||||
|
||||
/* ── 预设选项按「输出语言」过滤 ───────────────────────────────
|
||||
* 预设名的语言标签形如 "Z-Image Turbo [ZH]" / "Normal - 描述 [EN]";
|
||||
* 输出语言选中文 → 增强预设 / 反推预设 只列 [ZH] 项,选英文 → 只列 [EN] 项。 */
|
||||
function xbrLangTagOf(v) {
|
||||
const m = String(v == null ? "" : v).match(/[\[[](ZH|EN)[\]]]\s*$/i);
|
||||
return m ? m[1].toUpperCase() : "";
|
||||
}
|
||||
function xbrFilterByLang(opts, lang) {
|
||||
const want = xbrLangTagOf(lang);
|
||||
if (!want) return opts.slice();
|
||||
const hit = opts.filter((o) => xbrLangTagOf(o) === want);
|
||||
return hit.length ? hit : opts.slice(); // 全无语言标签(老预设)→ 全量兜底
|
||||
}
|
||||
/** 语言变了:优先换到「同名的另一语言项」,否则取该语言第一项 */
|
||||
function xbrSnapPreset(opts, cur, lang) {
|
||||
const list = xbrFilterByLang(opts, lang);
|
||||
if (list.includes(cur)) return cur;
|
||||
const base = String(cur == null ? "" : cur).replace(/\s*[\[[](ZH|EN)[\]]]\s*$/i, "").trim();
|
||||
const same = list.find((o) => String(o).replace(/\s*[\[[](ZH|EN)[\]]]\s*$/i, "").trim() === base);
|
||||
return same || list[0] || cur;
|
||||
}
|
||||
|
||||
/* ── 在线 API(存 ComfyUI user 目录,Key 不进工作流)──────── */
|
||||
async function xbrApiGet() {
|
||||
const resp = await api.fetchApi(XBR_API_ENDPOINT);
|
||||
@@ -3342,8 +3370,11 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
draft.lang = v;
|
||||
// 换语言 → 未在弹窗里改过设定词时,跟着取该语言的「存档 → 默认」
|
||||
if (!draft.presetTouched) draft.presetText = xbrPresetTextFor(node, draft.mode, v);
|
||||
// 语言决定预设可选范围:增强预设 / 反推预设 自动换到同语言的同名项(没有则取该语言第一项)
|
||||
draft.preset = xbrSnapPreset(xbrWidgetOptions(node, "preset"), draft.preset, v);
|
||||
draft.task_preset = xbrSnapPreset(xbrWidgetOptions(node, "task_preset"), draft.task_preset, v);
|
||||
})));
|
||||
body.append(xbrHint("本项是唯一的语言设置:① 元素词表 / 预设句按哪种语言加载 ② LLM 反推最终输出的提示词是中文还是英文。其他地方不再有语言选项。"));
|
||||
body.append(xbrHint("本项是唯一的语言设置:① 词表 / 设定词 / 预设句按哪种语言加载 ② 增强预设与反推预设只列该语言的选项 ③ 最终输出的提示词语言。"));
|
||||
|
||||
body.append(makeSectionTitle("提示词增强反推(总开关在节点表面的「启用 LLM 反推」)"));
|
||||
|
||||
@@ -3356,7 +3387,7 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
const llm = s.model;
|
||||
const models = lists.model.length ? lists.model : (llm.model ? [llm.model] : []);
|
||||
if (!llm.model && models.length) llm.model = models[0];
|
||||
body.append(field("强制卸载", checkboxControl(s.run.force_offload, "LLM 用完即卸载(释放显存)", (v) => { s.run.force_offload = v; })));
|
||||
body.append(field("强制卸载", checkboxControl(s.run.force_offload, "LLM 用完即卸载,释放显存", (v) => { s.run.force_offload = v; })));
|
||||
if (models.length) body.append(field("模型", selectControl(models, llm.model, (v) => { llm.model = v; })));
|
||||
else body.append(field("模型", xbrTextControl(llm.model, "未找到本地 LLM 模型(.gguf 放到 models/LLM)", (v) => { llm.model = v; })));
|
||||
body.append(field("视觉模块 mmproj", selectControl(lists.mmproj.length ? lists.mmproj : ["None"], llm.mmproj, (v) => { llm.mmproj = v; })));
|
||||
@@ -3386,7 +3417,7 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
const a = draft.api || (draft.api = { ...XBR_API_DEFAULTS });
|
||||
body.append(field("服务商", selectControl(ctx.providers, a.provider, (v) => { a.provider = v; })));
|
||||
body.append(field("模型", xbrTextControl(a.model, XBR_API_DEFAULTS.model, (v) => { a.model = v; })));
|
||||
body.append(field("API Key", xbrPasswordControl(a.api_key, "sk-…(保存在本地,不写入工作流)", (v) => { a.api_key = v; })));
|
||||
body.append(field("API Key", xbrPasswordControl(a.api_key, "sk-… 保存在本地,不写入工作流", (v) => { a.api_key = v; })));
|
||||
body.append(field("Base URL", xbrTextControl(a.base_url, XBR_API_DEFAULTS.base_url, (v) => { a.base_url = v; })));
|
||||
body.append(field("temperature", xbrNumberControl(a.temperature, { min: 0, max: 2, step: 0.01 }, (v) => { a.temperature = v; })));
|
||||
body.append(field("max_tokens", xbrNumberControl(a.max_tokens, { min: 1, max: 262144, step: 1 }, (v) => { a.max_tokens = Math.round(v); })));
|
||||
@@ -3402,8 +3433,13 @@ function xbrRenderLlm(body, node, draft, ctx) {
|
||||
body.append(field("推理模式", selectControl(XBR_INFERENCE_MODES, s.run.inference_mode, (v) => { s.run.inference_mode = v; })));
|
||||
body.append(field("最大帧数", xbrNumberControl(s.run.max_frames, { min: 2, max: 1024, step: 1 }, (v) => { s.run.max_frames = Math.round(v); })));
|
||||
body.append(field("最大尺寸", xbrNumberControl(s.run.max_size, { min: 128, max: 16384, step: 64 }, (v) => { s.run.max_size = Math.round(v); })));
|
||||
body.append(field("保存对话状态", checkboxControl(s.run.save_states, "在内存中保留本次对话上下文(多轮连续反推)", (v) => { s.run.save_states = v; })));
|
||||
body.append(field("保存对话状态", checkboxControl(s.run.save_states, "在内存中保留本次对话上下文,多轮连续反推", (v) => { s.run.save_states = v; })));
|
||||
body.append(field("状态 UID", xbrNumberControl(s.params.state_uid, { min: -1, max: 999999, step: 1 }, (v) => { s.params.state_uid = Math.round(v); })));
|
||||
body.append(field("🧠 过滤思考过程", checkboxControl(s.run.strip_thinking,
|
||||
"模型把「思考过程 / 推理段 / 工作流程」一起输出时,自动只保留最终提示词", (v) => { s.run.strip_thinking = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.65;margin:2px 0 8px;",
|
||||
"开启后=① 系统提示词末尾追加「只输出最终提示词」硬规则 ② 仍漏出思考时自动剔除思考标签、"
|
||||
+ "Final Output / 最终输出 标记之前的推理段与代码围栏(拿不到内容则原文保留)。"));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "提示词正文在节点上的提示词框里编辑;「📝 提示词」端口接线后该框锁定。"));
|
||||
}
|
||||
|
||||
@@ -3421,7 +3457,7 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
draft.presetText = xbrPresetTextFor(node, v, draft.lang);
|
||||
ctx.rerender(); // 有/无设定词的模式之间切换 → 重画「设定词」区
|
||||
})));
|
||||
body.append(xbrHint("常规文生图 = 只输出正文;人物三视图 / 人物四视图 / 背景纯透明 = 最终提示词最顶端自动加上该模式的设定词。"));
|
||||
body.append(xbrHint("常规文生图 = 只输出正文;人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 = 最终提示词最顶端自动加上该模式的设定词。"));
|
||||
|
||||
// ── 设定词(预设模式对应的设定文本;只在弹窗里编辑,节点表面不显示)──
|
||||
const modeDef = defaultPresetOf(draft.mode, draft.lang);
|
||||
@@ -3430,7 +3466,7 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
if (!String(draft.presetText || "").trim()) draft.presetText = modeDef;
|
||||
const taP = textareaControl(draft.presetText, (v) => { draft.presetText = v; draft.presetTouched = true; },
|
||||
"width:100%;box-sizing:border-box;min-height:180px;resize:vertical;");
|
||||
taP.placeholder = "该模式的设定词(改过的按「模式 + 语言」记进节点,换模式 / 换语言都不丢)";
|
||||
taP.placeholder = "该模式的设定词;改过的按「模式 + 语言」记进节点,换模式 / 换语言都不丢";
|
||||
taP.spellcheck = false;
|
||||
body.append(taP);
|
||||
const taRow = el("div", "display:flex;align-items:center;gap:10px;margin:6px 0 4px;");
|
||||
@@ -3449,19 +3485,20 @@ function xbrRenderPreset(body, node, draft, ctx) {
|
||||
}
|
||||
|
||||
body.append(makeSectionTitle("增强预设(= 提示词设定 / system prompt)"));
|
||||
const presetOpts = xbrWidgetOptions(node, "preset");
|
||||
const presetOpts = xbrFilterByLang(xbrWidgetOptions(node, "preset"), draft.lang);
|
||||
if (presetOpts.length) body.append(field("增强预设", selectControl(presetOpts, draft.preset, (v) => { draft.preset = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "该预设内容即「🧩 提示词设定」输出的正文,同时作为 LLM 反推的系统提示词。"));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;",
|
||||
`该预设内容即「🧩 提示词设定」输出的正文,同时作为 LLM 反推的系统提示词;只列与输出语言 ${draft.lang} 相符的预设。`));
|
||||
|
||||
body.append(makeSectionTitle("反推预设"));
|
||||
const taskOpts = xbrWidgetOptions(node, "task_preset");
|
||||
const taskOpts = xbrFilterByLang(xbrWidgetOptions(node, "task_preset"), draft.lang);
|
||||
if (taskOpts.length) body.append(field("反推预设", selectControl(taskOpts, draft.task_preset, (v) => { draft.task_preset = v; })));
|
||||
body.append(el("div", "font-size:11px;color:#888;line-height:1.6;margin:2px 0 8px;", "带 * 的预设里 * 是必填占位符,由节点上的提示词框或外接「📝 提示词」填入。"));
|
||||
|
||||
body.append(makeSectionTitle("追加设定(可留空)"));
|
||||
const ta = textareaControl(s.extra_system, (v) => { s.extra_system = v; },
|
||||
"width:100%;box-sizing:border-box;min-height:200px;resize:vertical;");
|
||||
ta.placeholder = "追加在增强预设之后的额外要求(例:只输出一行、不要解释过程…)";
|
||||
ta.placeholder = "追加在增强预设之后的额外要求,例:只输出一行、不要解释过程…";
|
||||
ta.spellcheck = false;
|
||||
body.append(ta);
|
||||
}
|
||||
@@ -3476,22 +3513,26 @@ function xbrRenderHelp(body) {
|
||||
" · 🖼️ 图像:外接图像 / 视频帧(LLM 反推:图 → 提示词)",
|
||||
"",
|
||||
"【输出端口】",
|
||||
" · 📝 提示词:最终提示词(未启用 LLM = 拼装好的提示词;启用 LLM = 设定词原样置顶 + LLM 增强后的正文)",
|
||||
" · 📝 提示词:最终提示词。未启用 LLM = 拼装好的提示词;启用 LLM = 设定词原封不动置顶 + LLM 增强后的正文",
|
||||
" · 🖼️ 空latent:第二位。按「空latent类型」生成,官方 latent_format 逐字段对齐",
|
||||
" · 📋 提示词列表:按行拆分",
|
||||
" · 🧩 提示词设定:本次的提示词设定(增强预设 + 输出语言 + 追加设定)",
|
||||
" · 🖼️ 空latent:按「空latent类型」生成(官方 latent_format 逐字段对齐)",
|
||||
" · 🧩 提示词设定:本次的提示词设定,即增强预设 + 输出语言 + 追加设定",
|
||||
"",
|
||||
"【节点表面】",
|
||||
" · 第 1 行按钮:🤖 LLM设置(唯一语言设置 / 后端 / 采样参数)| ✨ 增强预设(空latent类型 / 预设模式 / 增强预设 / 反推预设 / 追加设定)| 📖 使用说明",
|
||||
" · 第 2 行按钮:8 个元素分类(点选项行加入/移除提示词,【添加详细描述】写补充说明)",
|
||||
" · ✅ 启用 LLM 反推:关(默认)= 原「生图提示词预设」行为;开 = 图/文 → 提示词",
|
||||
" · 设定词:预设模式(三视图 / 四视图 / 背景纯透明)的设定文本,在「✨ 增强预设」弹窗里编辑;"
|
||||
" · 设定词:预设模式(三视图 / 四视图 / 五视图 / 背景纯透明)的设定文本,在「✨ 增强预设」弹窗里编辑;"
|
||||
+ "改过的随节点保存,换模式 / 换语言不丢;输出时原封不动加在增强结果的顶端,也作为 LLM 的增强参考",
|
||||
" · 提示词框右上角「📋 复制」;下方「参数设定显示」实时显示当前配置",
|
||||
"",
|
||||
"【保存】",
|
||||
" · 弹窗底部:☑ 自动保存(默认开)+ 字号 + 界面缩放;「取消」丢弃未保存改动",
|
||||
" · 配置随工作流保存;在线 API 的 Key 存在 ComfyUI user 目录,不进工作流",
|
||||
"",
|
||||
"【语言 / 思考过程】",
|
||||
" · 输出语言(🤖 LLM设置)是唯一语言设置:决定词表与设定词按哪种语言加载、增强预设与反推预设只列哪种语言的选项、最终提示词的语言",
|
||||
" · 🧠 过滤思考过程(🤖 LLM设置 → 指令推理,默认开):系统提示词末尾追加「只输出最终提示词」硬规则;模型仍漏出思考过程时,自动剔掉思考标签、Final Output / 最终输出 之前的推理段与代码围栏",
|
||||
];
|
||||
body.append(el("div", "font-size:12px;color:#bbb;line-height:1.9;white-space:pre-wrap;font-family:ui-monospace,Consolas,monospace;", lines.join("\n")));
|
||||
}
|
||||
@@ -3511,10 +3552,13 @@ async function xbrOpenModal(node, panelId) {
|
||||
lang: xbrPick(String(xbrWidgetVal(node, "output_lang") ?? ""), LANGS, LANGS[0]),
|
||||
kind: xbrPick(String(xbrWidgetVal(node, "latent_kind") ?? ""), LATENT_KINDS, LATENT_KINDS[0]),
|
||||
mode: xbrPick(String(xbrWidgetVal(node, "preset_mode") ?? ""), MODES, MODES[0]),
|
||||
// 设定词(三视图/四视图/背景纯透明):弹窗内草稿 + 「用户是否改过」标记
|
||||
// 设定词(三视图/四视图/五视图/背景纯透明):弹窗内草稿 + 「用户是否改过」标记
|
||||
presetText: String(xbrWidgetVal(node, "three_view_text") ?? ""),
|
||||
presetTouched: false,
|
||||
};
|
||||
// 预设选项与输出语言对齐(旧工作流可能存着异语言的预设名)
|
||||
draft.preset = xbrSnapPreset(xbrWidgetOptions(node, "preset"), draft.preset, draft.lang);
|
||||
draft.task_preset = xbrSnapPreset(xbrWidgetOptions(node, "task_preset"), draft.task_preset, draft.lang);
|
||||
|
||||
let apiSaved = null, providers = [XBR_DEFAULT_PROVIDER];
|
||||
if (panelId === "llm") {
|
||||
|
||||
@@ -357,7 +357,30 @@
|
||||
}
|
||||
},
|
||||
"XB_ImagePromptPresetPro": {
|
||||
"display_name": "XB-BOX - 🖼️ Image Prompt Preset Pro"
|
||||
"display_name": "XB-BOX - 🖼️ Image Prompt Preset Pro",
|
||||
"description": "Image Prompt Preset + Prompt Enhance/Reverse fused: empty latent type + aspect params + 8-category element panel; optional LLM enhance/reverse (local model or online API, enhance preset / task preset / extra settings / sampling params). Outputs: prompt / prompt list / prompt settings / empty latent.",
|
||||
"inputs": {
|
||||
"latent_kind": { "name": "Empty Latent Type" },
|
||||
"output_lang": { "name": "Output Language" },
|
||||
"preset_mode": { "name": "Preset Mode" },
|
||||
"three_view_text": { "name": "Preset Text (3/4/5-view / transparent)" },
|
||||
"aspect_ratio": { "name": "Aspect Ratio" },
|
||||
"width": { "name": "Width" },
|
||||
"height": { "name": "Height" },
|
||||
"batch_size": { "name": "Batch Size" },
|
||||
"use_llm": { "name": "✅ Enable LLM Enhance" },
|
||||
"backend": { "name": "LLM Backend" },
|
||||
"preset": { "name": "Enhance Preset" },
|
||||
"task_preset": { "name": "Reverse Preset" },
|
||||
"text": { "name": "📝 Prompt" },
|
||||
"images": { "name": "🖼️ Image" }
|
||||
},
|
||||
"outputs": {
|
||||
"0": { "name": "📝 Prompt" },
|
||||
"1": { "name": "�️ Empty Latent" },
|
||||
"2": { "name": "📋 Prompt List" },
|
||||
"3": { "name": "🧩 Prompt Settings" }
|
||||
}
|
||||
},
|
||||
"XB_ImagePromptPreset": {
|
||||
"display_name": "XB-BOX - 🖼️ Image Prompt Preset",
|
||||
@@ -365,7 +388,7 @@
|
||||
"output_lang": { "name": "Output Language" },
|
||||
"preset_mode": { "name": "Preset Mode" },
|
||||
"latent_kind": { "name": "Empty Latent Type" },
|
||||
"three_view_text": { "name": "Preset Text (3-view/4-view/transparent)" },
|
||||
"three_view_text": { "name": "Preset Text (3/4/5-view / transparent)" },
|
||||
"aspect_ratio": { "name": "Aspect Ratio" },
|
||||
"width": { "name": "Width" },
|
||||
"height": { "name": "Height" },
|
||||
|
||||
@@ -5888,12 +5888,12 @@
|
||||
},
|
||||
"XB_ImagePromptPresetPro": {
|
||||
"display_name": "XB-BOX - 🖼️ 生图提示词预设Pro",
|
||||
"description": "生图提示词预设 + 提示词增强反推 融合:空latent类型/画幅参数 + 8 大类元素面板拼装提示词;可选 LLM 反推(本地模型或在线 API,增强预设 / 反推预设 / 追加设定 / 采样参数 / 生成后控制)。输出:提示词 / 提示词列表 / 提示词设定 / 空latent。",
|
||||
"description": "生图提示词预设 + 提示词增强反推 融合:空latent类型/画幅参数 + 8 大类元素面板拼装提示词;可选 LLM 反推(本地模型或在线 API,增强预设 / 反推预设 / 追加设定 / 采样参数 / 生成后控制)。输出:提示词 / 空latent / 提示词列表 / 提示词设定。",
|
||||
"inputs": {
|
||||
"latent_kind": { "name": "空latent类型" },
|
||||
"output_lang": { "name": "输出语言" },
|
||||
"preset_mode": { "name": "预设模式" },
|
||||
"three_view_text": { "name": "预设句(三视图/四视图/透明背景)" },
|
||||
"three_view_text": { "name": "预设句(三/四/五视图·透明背景)" },
|
||||
"aspect_ratio": { "name": "画幅比例" },
|
||||
"width": { "name": "宽度" },
|
||||
"height": { "name": "高度" },
|
||||
@@ -5907,9 +5907,9 @@
|
||||
},
|
||||
"outputs": {
|
||||
"0": { "name": "📝 提示词" },
|
||||
"1": { "name": "📋 提示词列表" },
|
||||
"2": { "name": "🧩 提示词设定" },
|
||||
"3": { "name": "🖼️ 空latent" }
|
||||
"1": { "name": "�️ 空latent" },
|
||||
"2": { "name": "📋 提示词列表" },
|
||||
"3": { "name": "🧩 提示词设定" }
|
||||
}
|
||||
},
|
||||
"XB_ImagePromptPreset": {
|
||||
@@ -5918,7 +5918,7 @@
|
||||
"output_lang": { "name": "输出语言" },
|
||||
"preset_mode": { "name": "预设模式" },
|
||||
"latent_kind": { "name": "空latent类型" },
|
||||
"three_view_text": { "name": "预设句(三视图/四视图/透明背景)" },
|
||||
"three_view_text": { "name": "预设句(三/四/五视图·透明背景)" },
|
||||
"aspect_ratio": { "name": "画幅比例" },
|
||||
"width": { "name": "宽度" },
|
||||
"height": { "name": "高度" },
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
一个节点顶替「提示词输入框 + 画幅比例节点 + 官方空 latent」三件套:
|
||||
|
||||
· 表面参数(顺序 = 节点上从上到下的显示顺序):
|
||||
空latent类型 / 输出语言 / 预设模式 / 预设句(三视图·四视图·背景纯透明 三个模式显示)
|
||||
空latent类型 / 输出语言 / 预设模式 / 预设句(三视图·四视图·五视图·背景纯透明 四个模式显示)
|
||||
/ 画幅比例 / 宽度 / 高度 / 生成数量
|
||||
—— 画幅比例 + 步长锁定 + 比例联动 100% 复刻本包「XB-BOX - 🖼️ 图片参数大全」
|
||||
(去掉强度(小数)/强度(整数)/缩放尺寸三项)
|
||||
@@ -11,7 +11,7 @@
|
||||
🏷️ 风格 | 🎥 视角 | 👤 主体 | 🎬 姿态 | 👚 装扮 | 🎒 道具 | 💡 光影 | 🏞️ 背景
|
||||
每个按钮打开**该分类**的独立面板;面板顶部「分类签」切换子类
|
||||
(例:风格 → 真人/动画/3D/绘画插画/特殊风格),选项行 = ➕ ➖ 选项名 添加详细描述
|
||||
· 输出①「提示词」= 预设句(人物三视图 / 人物四视图 / 背景纯透明;常规文生图无预设句)+ 正文(节点提示词框 ↔ 面板预览框双向同步)
|
||||
· 输出①「提示词」= 预设句(人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明;常规文生图无预设句)+ 正文(节点提示词框 ↔ 面板预览框双向同步)
|
||||
· 输出②「空latent」= 主流模型直接可用的空 latent(选项名 = 模型名,规格按官方 latent_format;
|
||||
通道数 / 下采样除数 / 步长 / 上下限 / batch 上限 / downscale 元数据逐项对齐):
|
||||
· Z-image 16 通道 · /8 · 步长 16 (官方 latent_format = Flux)
|
||||
@@ -52,20 +52,23 @@ MAX_RESOLUTION = int(getattr(nodes, "MAX_RESOLUTION", 16384) or 16384)
|
||||
|
||||
# ── 面板枚举(字符串即存储值,前端面板与后端按同一份字符串对齐) ────────────
|
||||
OUTPUT_LANGS = ["中文 [ZH]", "英文 [EN]"]
|
||||
PRESET_MODES = ["常规文生图", "人物三视图", "人物四视图", "背景纯透明"]
|
||||
PRESET_MODES = ["常规文生图", "人物三视图", "人物四视图", "人物五视图", "背景纯透明"]
|
||||
|
||||
LANG_ZH = OUTPUT_LANGS[0]
|
||||
MODE_TEXT2IMG = PRESET_MODES[0]
|
||||
MODE_THREE_VIEW = PRESET_MODES[1]
|
||||
MODE_FOUR_VIEW = PRESET_MODES[2]
|
||||
MODE_TRANSPARENT = PRESET_MODES[3]
|
||||
MODE_FIVE_VIEW = PRESET_MODES[3]
|
||||
MODE_TRANSPARENT = PRESET_MODES[4]
|
||||
|
||||
# ── 主流模型的空 latent 规格表(逐项抄自 ComfyUI:comfy/latent_formats.py + 官方空 latent 节点)──
|
||||
# 选项文字 = 模型名(干净,不带专业参数;细节放 tooltip 与日志);规格仍完整保留以保证对得上模型:
|
||||
# 每行: (选项名, 通道数, 下采样除数_h, _w, 尺寸步长, 最小, 最大, batch上限, downscale_ratio_spacial)# · 尺寸步长 = 各模型**官方最小步长**(= 下采样 × patch2):
|
||||
# 每行: (选项名, 通道数, 下采样除数_h, _w, 尺寸步长, 最小, 最大, batch上限, downscale_ratio_spacial)
|
||||
# · 尺寸步长 = 各模型**官方最小步长**(= 下采样 × patch2):
|
||||
# Anima/Boogu/SDXL = 8(/8)、Flux2 = 16(/16)、Krea2/SD3/Z-image = 16(/8×patch2)、
|
||||
# Qwen-image = 32(用户指定:Qwen 系工作流习惯锁 32)、Hunyuan = 32(/32)。
|
||||
# 不做全局统一的 32,避免把 1080 这类尺寸无谓地顶到 1088。# · downscale_ratio_spacial = 官方 EmptyLatentImage/EmptySD3 带回的元数据(供
|
||||
# 不做全局统一的 32,避免把 1080 这类尺寸无谓地顶到 1088。
|
||||
# · downscale_ratio_spacial = 官方 EmptyLatentImage/EmptySD3 带回的元数据(供
|
||||
# comfy/sample.py:fix_empty_latent_channels 判断是否需要缩放尺寸)
|
||||
_OFFICIAL_LATENT_ROWS = [
|
||||
("Anima", 16, 8, 8, 8, 16, MAX_RESOLUTION, 4096, 8),
|
||||
@@ -92,7 +95,7 @@ LATENT_KIND_SPEC = {
|
||||
DEFAULT_LATENT_KIND = "Z-image"
|
||||
# 各预设模式的默认预设句(可编辑字段 three_view_text 的默认值):按「预设模式 × 输出语言」给。
|
||||
# · 常规文生图 = 无预设句(原样输出正文,用户完全可控)
|
||||
# · 人物三视图 / 人物四视图 / 背景纯透明 = 成句时自动把预设句拼在正文前(中文「。」/英文 ". ")
|
||||
# · 人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 = 成句时自动把预设句拼在正文前(中文「。」/英文 ". ")
|
||||
PRESET_TEXT = {
|
||||
MODE_THREE_VIEW: {
|
||||
LANG_ZH: "生成平行排列的角色概念设计图,画面从左到右由四个独立面板组成:"
|
||||
@@ -115,11 +118,24 @@ PRESET_TEXT = {
|
||||
"the bottom-left panel is a headless front-facing outfit display view, "
|
||||
"the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
MODE_FIVE_VIEW: {
|
||||
LANG_ZH: "生成五宫格排列的角色概念设计图,画面左上角面板是角色面部的精细特写肖像,"
|
||||
"画面右上角面板是角色面部侧面的的精细特写肖像,"
|
||||
"画面下方左侧面板是无头部人物正面衣着展示图,画面下方中间面板是无头部人物侧面衣着展示图,"
|
||||
"画面下方右侧面板是人物背面全身站姿。",
|
||||
OUTPUT_LANGS[1]: "Generate a character concept design sheet arranged in five panels, "
|
||||
"the top-left panel is a finely detailed close-up portrait of the character's face, "
|
||||
"the top-right panel is a finely detailed close-up profile portrait of the character's face, "
|
||||
"the bottom-left panel is a headless front-facing outfit display view, "
|
||||
"the bottom-middle panel is a headless side-facing outfit display view, "
|
||||
"the bottom-right panel is a full-body back standing pose.",
|
||||
},
|
||||
MODE_TRANSPARENT: {
|
||||
LANG_ZH: "生成一张具有透明度的 RGBA 格式图像,包含 Alpha 通道,背景为纯透明。",
|
||||
OUTPUT_LANGS[1]: "Generate an RGBA image with an alpha channel and a fully transparent background.",
|
||||
},
|
||||
}
|
||||
|
||||
# 兼容旧引用(三视图预设句)
|
||||
THREE_VIEW_TEXT = PRESET_TEXT[MODE_THREE_VIEW]
|
||||
|
||||
@@ -322,7 +338,7 @@ def build_empty_latent(latent_kind, width, height, batch_size=1):
|
||||
# 提示词拼装
|
||||
# ============================================================================
|
||||
def build_prompt(lang, preset_mode, three_view_text, body):
|
||||
"""预设句(人物三视图 / 人物四视图 / 背景纯透明) + 正文,按输出语言使用合适的分句符。
|
||||
"""预设句(人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明) + 正文,按输出语言使用合适的分句符。
|
||||
|
||||
正文 = 节点表面提示词框(也等于面板预览框,两者双向同步)。
|
||||
常规文生图:预设句不参与 → 原样输出正文(保持用户完全可控)。
|
||||
@@ -347,7 +363,7 @@ def build_prompt(lang, preset_mode, three_view_text, body):
|
||||
class XB_ImagePromptPreset:
|
||||
"""XB-BOX - 🖼️ 生图提示词预设:画幅参数 + 提示词拼装 + 官方空 latent 一体化。
|
||||
|
||||
· 表面参数顺序 = 输出语言 / 预设模式 / 空latent类型 / 预设句(三视图·四视图·背景纯透明 显示)
|
||||
· 表面参数顺序 = 输出语言 / 预设模式 / 空latent类型 / 预设句(三视图·四视图·五视图·背景纯透明 显示)
|
||||
/ 画幅比例 / 宽度 / 高度 / 生成数量;
|
||||
· 「提示词」输出 = 预设句(人物三视图)+ 节点提示词框正文;
|
||||
· 「空latent」输出 = 官方空 latent(见 LATENT_KINDS,共 9 种,逐字段对齐,选项按首字母排列)。
|
||||
@@ -374,12 +390,12 @@ class XB_ImagePromptPreset:
|
||||
"preset_mode": (list(PRESET_MODES), {
|
||||
"default": PRESET_MODES[0],
|
||||
"tooltip": "预设模式:常规文生图=只输出正文(完全可控);"
|
||||
"人物三视图 / 人物四视图 / 背景纯透明 = 成句自动在正文前加对应预设句"
|
||||
"人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 = 成句自动在正文前加对应预设句"
|
||||
"(下方预设句框仅这三个模式显示,切模式时未改过的默认句会自动跟随)",
|
||||
}),
|
||||
"three_view_text": ("STRING", {
|
||||
"default": THREE_VIEW_TEXT[LANG_ZH], "multiline": True,
|
||||
"tooltip": "预设句 / 设定词(人物三视图 / 人物四视图 / 背景纯透明 三个模式生效;常规文生图时本框自动隐藏)\n"
|
||||
"tooltip": "预设句 / 设定词(人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 四个模式生效;常规文生图时本框自动隐藏)\n"
|
||||
"· 用户改过的设定词按「模式 + 语言」存进本节点(换模式 / 换语言都不会丢);\n"
|
||||
"· 最终提示词输出时它会被原封不动加在正文最顶端",
|
||||
}),
|
||||
@@ -407,7 +423,7 @@ class XB_ImagePromptPreset:
|
||||
"internal_prompt": ("STRING", {
|
||||
"default": "", "multiline": True,
|
||||
"tooltip": "节点内编辑的提示词正文(与元素面板的预览框双向同步,随工作流保存)。"
|
||||
"人物三视图 / 人物四视图 / 背景纯透明模式下,本字段前面会自动拼上对应预设句",
|
||||
"人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明模式下,本字段前面会自动拼上对应预设句",
|
||||
}),
|
||||
"manager_settings": ("STRING", {
|
||||
"default": "", "multiline": True,
|
||||
@@ -465,7 +481,7 @@ class XB_ImagePromptPreset:
|
||||
__all__ = [
|
||||
"XB_ImagePromptPreset",
|
||||
"ASPECT_RATIO_OPTIONS", "ASPECT_RATIO_MAP", "SIZE_STEP", "SIZE_MIN", "MAX_RESOLUTION",
|
||||
"BATCH_MAX", "OUTPUT_LANGS", "PRESET_MODES", "PRESET_TEXT", "THREE_VIEW_TEXT",
|
||||
"BATCH_MAX", "MODE_FIVE_VIEW", "OUTPUT_LANGS", "PRESET_MODES", "PRESET_TEXT", "THREE_VIEW_TEXT",
|
||||
"LATENT_KINDS", "LATENT_KIND_SPEC", "DEFAULT_LATENT_KIND", "ELEMENT_CATEGORIES",
|
||||
"default_settings", "parse_settings", "round_step", "normalize_size",
|
||||
"latent_kind_spec", "latent_step_of", "latent_shape_of",
|
||||
|
||||
@@ -5,7 +5,7 @@ XB-BOX - 🖼️ 生图提示词预设Pro
|
||||
|
||||
① 生图预设(原节点全部能力)
|
||||
· 空latent类型(9 种主流模型,逐字段对齐官方 latent_format)
|
||||
· 输出语言 / 预设模式 / 设定词(三视图·四视图·背景纯透明)
|
||||
· 输出语言 / 预设模式 / 设定词(三视图·四视图·五视图·背景纯透明)
|
||||
- 设定词既作为 LLM 的**增强参考**,也(启用 LLM 时)被**原封不动**加在最终提示词最顶端;
|
||||
- 用户改过的设定词按「模式 + 语言」存在本节点里,换模式 / 换语言都不会丢。
|
||||
· 画幅比例 / 宽度 / 高度 / 生成数量(步长按模型官方最小步长 8/16/32 + 比例联动)
|
||||
@@ -22,7 +22,7 @@ XB-BOX - 🖼️ 生图提示词预设Pro
|
||||
· 关(默认)= 原「生图提示词预设」行为:只输出拼装好的提示词 + 空latent(不加载模型、不调 API)
|
||||
· 开 = 把(外接「提示词」端口 或 节点上拼装好的提示词)+ 外接「图像」交给 LLM 反推
|
||||
|
||||
输出:提示词(最终)/ 提示词列表 / 提示词设定 / 空latent
|
||||
输出:提示词(最终)/ 空latent / 提示词列表 / 提示词设定
|
||||
(两个旧节点全部保留,本节点只是融合超集)
|
||||
|
||||
CATEGORY: XB_ToolBox/Image_Params
|
||||
@@ -38,11 +38,13 @@ from .nodes_llama import (
|
||||
preset_tags,
|
||||
)
|
||||
from .nodes_llama_prompt_reverse import (
|
||||
OUTPUT_FORMAT_HINT,
|
||||
_LANG_HINT,
|
||||
_OUTPUT_LANGS,
|
||||
_SEED_MAX,
|
||||
build_api_config,
|
||||
parse_settings as parse_llm_settings,
|
||||
strip_reasoning,
|
||||
)
|
||||
from .nodes_image_prompt_preset import (
|
||||
ASPECT_RATIO_OPTIONS,
|
||||
@@ -102,10 +104,11 @@ def _next_seed(seed, mode):
|
||||
|
||||
|
||||
def _build_system_prompt(preset, extra, output_lang, preset_text=""):
|
||||
"""提示词设定 = 增强预设 + 输出语言 + 设定词参考 + 追加设定
|
||||
"""提示词设定 = 增强预设 + 输出语言 + 设定词参考 + 追加设定 + 只输出最终提示词的硬规则
|
||||
|
||||
`preset_text`(预设模式的设定词)只作为**增强参考**告诉 LLM:它会被节点原样置顶到最终提示词,
|
||||
禁止在正文里重复 / 改写它。
|
||||
最后追加 `OUTPUT_FORMAT_HINT`(最高优先级)——专治模型把思考过程 / 步骤 / 说明一起输出。
|
||||
"""
|
||||
parts = [XB_llamaPromptEnhancer().main(preset)[0] or ""]
|
||||
parts.append(_LANG_HINT.get(output_lang, _LANG_HINT[_OUTPUT_LANGS[0]]))
|
||||
@@ -115,6 +118,7 @@ def _build_system_prompt(preset, extra, output_lang, preset_text=""):
|
||||
extra = (extra or "").strip()
|
||||
if extra:
|
||||
parts.append(extra)
|
||||
parts.append(OUTPUT_FORMAT_HINT) # 放最后 = 最显眼(用户要求:不要思考过程)
|
||||
return "\n\n".join([p for p in parts if p])
|
||||
|
||||
|
||||
@@ -154,11 +158,11 @@ class XB_ImagePromptPresetPro:
|
||||
}),
|
||||
"preset_mode": (list(PRESET_MODES), {
|
||||
"default": PRESET_MODES[0],
|
||||
"tooltip": "预设模式:常规文生图=只输出正文;人物三视图 / 人物四视图 / 背景纯透明 = 自动在正文前加预设句",
|
||||
"tooltip": "预设模式:常规文生图=只输出正文;人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 = 自动在正文前加预设句",
|
||||
}),
|
||||
"three_view_text": ("STRING", {
|
||||
"default": THREE_VIEW_TEXT[DEFAULT_LANG], "multiline": True,
|
||||
"tooltip": "预设模式的设定词(人物三视图 / 人物四视图 / 背景纯透明 三个模式生效;常规文生图时自动隐藏)\n"
|
||||
"tooltip": "预设模式的设定词(人物三视图 / 人物四视图 / 人物五视图 / 背景纯透明 四个模式生效;常规文生图时自动隐藏)\n"
|
||||
"· 最终提示词输出时它会被【原封不动】加在最顶端;\n"
|
||||
"· 用户改过的设定词按「模式 + 语言」存进本节点(换模式 / 换语言都不会丢);\n"
|
||||
"· 启用 LLM 时它作为增强参考交给 LLM(LLM 只增强正文,不改写它)",
|
||||
@@ -227,14 +231,14 @@ class XB_ImagePromptPresetPro:
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING", "STRING", "STRING", "LATENT")
|
||||
RETURN_NAMES = ("提示词", "提示词列表", "提示词设定", "空latent")
|
||||
OUTPUT_IS_LIST = (False, True, False, False)
|
||||
RETURN_TYPES = ("STRING", "LATENT", "STRING", "STRING")
|
||||
RETURN_NAMES = ("提示词", "空latent", "提示词列表", "提示词设定")
|
||||
OUTPUT_IS_LIST = (False, False, True, False)
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "XB_ToolBox/Image_Params"
|
||||
DESCRIPTION = ("生图提示词预设Pro:生图预设(空latent类型/输出语言/预设模式/画幅参数 + 8 大类元素面板提示词拼装)"
|
||||
"+ LLM 提示词增强反推(本地模型或在线 API、增强预设、反推预设、追加设定、采样参数、生成后控制)。"
|
||||
"「启用 LLM 反推」关 = 原预设行为;开 = 图/文 → 提示词。输出:提示词 / 提示词列表 / 提示词设定 / 空latent。")
|
||||
"「启用 LLM 反推」关 = 原预设行为;开 = 图/文 → 提示词。输出:提示词 / 空latent / 提示词列表 / 提示词设定。")
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, manager_settings="", **kwargs):
|
||||
@@ -313,8 +317,13 @@ class XB_ImagePromptPresetPro:
|
||||
images=images,
|
||||
queue_handler=None,
|
||||
)
|
||||
# ④c 设定词**原封不动**加在增强结果最顶端(与未启用 LLM 时的成句规则完全一致)
|
||||
final_prompt = build_prompt(output_lang, preset_mode, three_view_text, out1 or "")
|
||||
# ④c 思考过程过滤(模型无视规则、把推理段一起输出时只留最终提示词)
|
||||
raw_out = out1 or ""
|
||||
body_out = strip_reasoning(raw_out) if run.get("strip_thinking", True) else raw_out
|
||||
if body_out != raw_out.strip():
|
||||
print(f"[XB-生图预设Pro] 🧠 已过滤思考过程:{len(raw_out)} 字 → {len(body_out)} 字")
|
||||
# ④d 设定词**原封不动**加在增强结果最顶端(与未启用 LLM 时的成句规则完全一致)
|
||||
final_prompt = build_prompt(output_lang, preset_mode, three_view_text, body_out)
|
||||
else:
|
||||
# 原「🖼️ 生图提示词预设」行为:直接输出拼装好的提示词
|
||||
final_prompt = base_prompt
|
||||
@@ -338,7 +347,7 @@ class XB_ImagePromptPresetPro:
|
||||
}
|
||||
if use_llm and next_seed is not None:
|
||||
ui["seed"] = [next_seed] # 前端回写到 manager_settings.llm.run.seed(仅 LLM 采样时才推进种子)
|
||||
return {"ui": ui, "result": (final_prompt, prompt_list, full_system or "", latent)}
|
||||
return {"ui": ui, "result": (final_prompt, latent, prompt_list, full_system or "")}
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
|
||||
@@ -23,6 +23,7 @@ CATEGORY: XB-llama
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
||||
import folder_paths
|
||||
from aiohttp import web
|
||||
@@ -141,6 +142,7 @@ DEFAULT_SETTINGS = {
|
||||
"run": {
|
||||
"inference_mode": "one by one", "max_frames": 24, "max_size": 256,
|
||||
"seed": 0, "seed_control": "randomize", "force_offload": False, "save_states": False,
|
||||
"strip_thinking": True, # 模型把「思考过程 / 推理段」一起输出时,只保留最终提示词
|
||||
},
|
||||
# 推理参数(原「⚙️ 推理参数」)
|
||||
"params": {
|
||||
@@ -166,6 +168,88 @@ _LANG_HINT = {
|
||||
"英文 [EN]": "【Output language】Always respond in English.",
|
||||
}
|
||||
|
||||
# 「只输出最终提示词」硬规则:拼在系统提示词最后,专治模型把思考过程/步骤/说明一起输出
|
||||
OUTPUT_FORMAT_HINT = (
|
||||
"【输出格式(最高优先级,凌驾于以上所有说明)】\n"
|
||||
"直接输出最终提示词本身,不要输出思考过程、推理步骤、分析、工作流程、小标题、编号列表、"
|
||||
"对以上说明的复述、代码块围栏(```),也不要任何开场白、总结或解释。"
|
||||
)
|
||||
|
||||
# ── 思考过程过滤(模型无视上面的规则、把推理段一起吐出来时的兜底)──────────────
|
||||
_THINK_BLOCK_RE = re.compile(r"<(thinking|think|analysis|reasoning)\b[^>]*>.*?</\1>", re.S | re.I)
|
||||
_THINK_CLOSE_RE = re.compile(r"</(thinking|think|analysis|reasoning)>", re.I)
|
||||
_THINK_HEADERS = ("thinking process", "think process", "reasoning process", "chain of thought",
|
||||
"思考过程", "推理过程", "分析过程", "思维过程", "思路如下", "先分析")
|
||||
_ANSWER_MARKERS = ("final output", "final answer", "final prompt",
|
||||
"最终输出", "最终答案", "最终提示词", "最终结果", "成品提示词", "输出结果")
|
||||
|
||||
|
||||
def _looks_like_reasoning(block):
|
||||
"""判断一个段落块像「推理 / 草稿 / 清单」而不是成品提示词"""
|
||||
b = block.strip()
|
||||
if not b:
|
||||
return False
|
||||
if b.startswith(("*", "_", "-", ">", "#", "```", "|")):
|
||||
return True
|
||||
if re.match(r"^\**(?:\d+[\.\、\))]|[-*•])\s*\**", b):
|
||||
return True
|
||||
if "**" in b and len(b) < 400:
|
||||
return True
|
||||
if re.match(r"^\**[^。!?\n]{0,30}[::]\**\s*$", b):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def strip_reasoning(text):
|
||||
"""丢掉模型输出里的「思考过程」,只留最终提示词。
|
||||
|
||||
① 显式思考块 <thinking>…</thinking> / <analysis>…</analysis> → 删;只有闭合标签 → 取其后的内容
|
||||
② 显式「最终输出 / Final Output」标记 → 取最后一个标记之后的正文
|
||||
③ 开头是思考标题(Thinking Process / 思考过程…)→ 从尾部往回收集「成品段落」,丢掉前面的推理段
|
||||
④ 去掉整段代码围栏,并去掉首尾空白
|
||||
任何一步拿不到内容都回退原文(绝不把结果清空)。
|
||||
"""
|
||||
raw = text if isinstance(text, str) else ""
|
||||
s = raw.strip()
|
||||
if not s:
|
||||
return raw
|
||||
original = s
|
||||
|
||||
s2 = _THINK_BLOCK_RE.sub("", s) # ①
|
||||
closes = list(_THINK_CLOSE_RE.finditer(s2))
|
||||
if closes:
|
||||
s2 = s2[closes[-1].end():]
|
||||
s = s2.strip() or s
|
||||
|
||||
low = s.lower() # ②
|
||||
best, hit_len = -1, 0
|
||||
for marker in _ANSWER_MARKERS:
|
||||
i = low.rfind(marker)
|
||||
if i > best:
|
||||
best, hit_len = i, len(marker)
|
||||
if best >= 0:
|
||||
tail = s[best + hit_len:]
|
||||
nl = tail.find("\n")
|
||||
if nl >= 0:
|
||||
tail = tail[nl + 1:]
|
||||
tail = tail.lstrip(":: \t-—").strip() # 支持「最终输出:xxx」同行写法
|
||||
if tail:
|
||||
s = tail
|
||||
|
||||
head = s[:400].lower() # ③
|
||||
if any(h in head for h in _THINK_HEADERS):
|
||||
blocks = [b for b in re.split(r"\n\s*\n", s) if b.strip()]
|
||||
keep = []
|
||||
for b in reversed(blocks):
|
||||
if _looks_like_reasoning(b):
|
||||
break
|
||||
keep.append(b)
|
||||
if keep:
|
||||
s = "\n\n".join(reversed(keep)).strip()
|
||||
|
||||
s = re.sub(r"^```[a-zA-Z]*\s*|\s*```$", "", s.strip()).strip() # ④
|
||||
return s or original
|
||||
|
||||
|
||||
def _num(value, default, lo=None, hi=None):
|
||||
try:
|
||||
@@ -237,6 +321,7 @@ def parse_settings(raw):
|
||||
rd["seed_control"] = _pick(r.get("seed_control"), _SEED_MODES, rd["seed_control"])
|
||||
rd["force_offload"] = _bool(r.get("force_offload"), rd["force_offload"])
|
||||
rd["save_states"] = _bool(r.get("save_states"), rd["save_states"])
|
||||
rd["strip_thinking"] = _bool(r.get("strip_thinking"), rd["strip_thinking"])
|
||||
|
||||
p = data.get("params") if isinstance(data.get("params"), dict) else {}
|
||||
pd = out["params"]
|
||||
|
||||
Reference in New Issue
Block a user