From 9abc04f5e591820732a72df799f16e76ec130f70 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sun, 23 Apr 2023 12:06:12 +0100 Subject: [PATCH] Ability to use preset text anywhere --- preset-text/presetText.js | 108 +++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 14 deletions(-) diff --git a/preset-text/presetText.js b/preset-text/presetText.js index c823465..7720a21 100644 --- a/preset-text/presetText.js +++ b/preset-text/presetText.js @@ -1,30 +1,60 @@ import { app } from "/scripts/app.js"; // Allows you to manage preset tags for e.g. common negative prompt +// Also performs replacements on any text field e.g. allowing you to use preset text in CLIP Text encode fields + +let replaceRegex; +const id = "pysssss.PresetText.Presets"; + +const getPresets = () => { + let items; + try { + items = JSON.parse(localStorage.getItem(id)); + } catch (error) {} + if (!items || !items.length) { + items = [{ name: "default negative", value: "worst quality" }]; + } + return items; +}; + +let presets = getPresets(); app.registerExtension({ name: "pysssss.PresetText", + setup() { + app.ui.settings.addSetting({ + id: "pysssss.PresetText.ReplacementRegex", + name: "[pysssss] Preset Text Replacement Regex", + type: "text", + defaultValue: "(?:^|[^\\w])(?@(?[\\w-]+))", + tooltip: + "The regex should return two named capture groups: id (the name of the preset text to use), replace (the matched text to replace)", + attrs: { + style: { + fontFamily: "monospace", + }, + }, + onChange(value) { + if (!value) { + replaceRegex = null; + return; + } + try { + replaceRegex = new RegExp(value, "g"); + } catch (error) { + alert("Error creating regex for preset text replacement, no replacements will be performed."); + replaceRegex = null; + } + }, + }); + }, registerCustomNodes() { class PresetTextNode { constructor() { this.isVirtualNode = true; this.serialize_widgets = true; - - const id = "pysssss.PresetText.Presets"; - const getPresets = () => { - let items; - try { - items = JSON.parse(localStorage.getItem(id)); - } catch (error) {} - if (!items || !items.length) { - items = [{ name: "default negative", value: "worst quality" }]; - } - return items; - }; - this.addOutput("text", "STRING"); - let presets = getPresets(); const widget = this.addWidget("combo", "value", presets[0].name, () => {}, { values: presets.map((p) => p.name), }); @@ -139,4 +169,54 @@ app.registerExtension({ PresetTextNode.category = "utils"; }, + nodeCreated(node) { + if (node.widgets) { + // Locate dynamic prompt text widgets + const widgets = node.widgets.filter((n) => n.type === "customtext" || n.type === "text"); + for (const widget of widgets) { + const callbacks = [ + () => { + let prompt = widget.value; + if (replaceRegex) { + prompt = prompt.replace(replaceRegex, (match, p1, p2, index, text, groups) => { + if (!groups.replace || !groups.id) return match; // No match, bad regex? + + const preset = presets.find((p) => p.name.replaceAll(/\s/g, "-") === groups.id); + if (!preset) return match; // Invalid name + + const pos = match.indexOf(groups.replace); + return match.substring(0, pos) + preset.value; + }); + } + return prompt; + }, + ]; + if (widget.serializeValue) { + callbacks.push(widget.serializeValue); + } + + const serializeValue = (workflowNode, widgetIndex) => { + const widgetValue = widget.value; + + for (const cb of callbacks) { + widget.value = cb(workflowNode, widgetIndex); + } + + const prompt = widget.value; + widget.value = widgetValue; + + return prompt; + }; + + Object.defineProperty(widget, "serializeValue", { + get() { + return serializeValue; + }, + set(cb) { + callbacks.push(cb); + }, + }); + } + } + }, });