Add saved prompt library node
This commit is contained in:
+37
-1
@@ -55,8 +55,44 @@ async def _delete(request):
|
||||
return web.json_response(ideas)
|
||||
|
||||
|
||||
def _library_path():
|
||||
return image_library.store_dir() / "prompt_library.json"
|
||||
|
||||
|
||||
def _library_read():
|
||||
try:
|
||||
return json.loads(_library_path().read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError):
|
||||
return {}
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/promptforge/prompts")
|
||||
async def _prompts(request):
|
||||
return web.json_response(_library_read())
|
||||
|
||||
|
||||
@PromptServer.instance.routes.post("/promptforge/prompts")
|
||||
async def _prompts_save(request):
|
||||
body = await request.json()
|
||||
name = str(body.get("name", "")).strip()
|
||||
if not name:
|
||||
return web.json_response({"error": "a prompt needs a name"}, status=400)
|
||||
data = _library_read()
|
||||
data[name] = str(body.get("text", ""))
|
||||
_library_path().write_text(json.dumps(data, indent=1, ensure_ascii=False), encoding="utf-8")
|
||||
return web.json_response(data)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.delete("/promptforge/prompts")
|
||||
async def _prompts_delete(request):
|
||||
data = _library_read()
|
||||
data.pop(request.query.get("name", ""), None)
|
||||
_library_path().write_text(json.dumps(data, indent=1, ensure_ascii=False), encoding="utf-8")
|
||||
return web.json_response(data)
|
||||
|
||||
|
||||
@PromptServer.instance.routes.get("/promptforge/actions")
|
||||
async def _actions(request):
|
||||
return web.json_response({label: {"roles": h3_actions.role_info(label), "aspect": h3_actions.aspect(label),
|
||||
"category": h3_actions.action_category(label), "cameras": h3_actions.cameras(label)}
|
||||
"category": h3_actions.action_category(label), "cameras": h3_actions.cameras(label), "penetration": h3_actions.penetration_modes(label)}
|
||||
for label in h3_actions.ACTIONS})
|
||||
|
||||
@@ -95,6 +95,20 @@ class PROMPTFORGE_KreaEditEncode:
|
||||
return positive, negative_out
|
||||
|
||||
|
||||
class PROMPTFORGE_PromptLibrary:
|
||||
"""A saved prompt you can switch quickly; the bar comes from the browser side."""
|
||||
CATEGORY = "🔮 PromptForge/Prompts"
|
||||
RETURN_TYPES = ("STRING",)
|
||||
FUNCTION = "get"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required": {"text": ("STRING", {"default": "", "multiline": True, "tooltip": "Use the bar to load, save or delete prompts."})}}
|
||||
|
||||
def get(self, text):
|
||||
return (text,)
|
||||
|
||||
|
||||
EDIT_LORAS = {
|
||||
"Krea 2": "Krea 2/tool/krea2_identity_edit_v2.safetensors",
|
||||
"MOSS Image": "MOSS Image/tool/moss_image_edit_lora_rank_64_bf16.safetensors",
|
||||
@@ -270,6 +284,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"PROMPTFORGE_TextEncode": PROMPTFORGE_TextEncode,
|
||||
"PROMPTFORGE_MossEditEncode": PROMPTFORGE_MossEditEncode,
|
||||
"PROMPTFORGE_KreaEditEncode": PROMPTFORGE_KreaEditEncode,
|
||||
"PROMPTFORGE_PromptLibrary": PROMPTFORGE_PromptLibrary,
|
||||
"PROMPTFORGE_EditLora": PROMPTFORGE_EditLora,
|
||||
"PROMPTFORGE_KreaNAG": PROMPTFORGE_KreaNAG,
|
||||
"PROMPTFORGE_KreaEditModelPatch": PROMPTFORGE_KreaEditModelPatch,
|
||||
@@ -282,6 +297,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"PROMPTFORGE_TextEncode": "PromptForge Text Encode",
|
||||
"PROMPTFORGE_MossEditEncode": "PromptForge MOSS Edit Encode",
|
||||
"PROMPTFORGE_KreaEditEncode": "PromptForge Krea Edit Encode",
|
||||
"PROMPTFORGE_PromptLibrary": "PromptForge Prompt Library",
|
||||
"PROMPTFORGE_EditLora": "PromptForge Edit LoRA",
|
||||
"PROMPTFORGE_KreaNAG": "PromptForge Krea NAG",
|
||||
"PROMPTFORGE_KreaEditModelPatch": "PromptForge Krea Edit Model Patch",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "ComfyUI-PromptForge"
|
||||
description = "ComfyUI prompt enhancement suite: model/config node with GPU-aware auto settings, prompt enhancer with a preset catalog, and a standalone config finder."
|
||||
version = "1.28.30"
|
||||
version = "1.28.31"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = [
|
||||
"transformers",
|
||||
|
||||
@@ -10,6 +10,7 @@ const MODES = "PROMPTFORGE_H3Modes";
|
||||
const SECOND_STAGE = "PROMPTFORGE_H3SecondStage";
|
||||
const GENERATE = "PROMPTFORGE_H3Generate";
|
||||
const REFERENCES = "PROMPTFORGE_H3References";
|
||||
const LIBRARY = "PROMPTFORGE_PromptLibrary";
|
||||
const SUBJECT_DISABLED = "disabled (not in the video)";
|
||||
const ANY_CAMERA = "(writer's choice)";
|
||||
// the description box of a slot is shown only while its picture / video / sound is connected and the description is not itself wired
|
||||
@@ -456,6 +457,46 @@ app.registerExtension({
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodeData.name === LIBRARY) {
|
||||
const onCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
onCreated?.apply(this, arguments);
|
||||
const node = this;
|
||||
const text = node.widgets.find((widget) => widget.name === "text");
|
||||
const bar = el("div", { display: "flex", alignItems: "center", gap: "4px", fontSize: "12px", color: "var(--input-text, #ddd)" });
|
||||
const select = el("select", { ...INPUT, flex: "1 1 auto", minWidth: "0", height: "24px" });
|
||||
const previous = el("button", BUTTON, { textContent: "◀" });
|
||||
const next = el("button", BUTTON, { textContent: "▶" });
|
||||
const save = el("button", BUTTON, { textContent: "Save" });
|
||||
const saveAs = el("button", BUTTON, { textContent: "Save as…" });
|
||||
const remove = el("button", BUTTON, { textContent: "Delete" });
|
||||
bar.append(el("span", { opacity: ".7" }, { textContent: "Prompts" }), previous, select, next, save, saveAs, remove);
|
||||
let prompts = {};
|
||||
const refresh = (chosen) => {
|
||||
select.replaceChildren(el("option", {}, { value: "", textContent: "— saved prompts —" }), ...Object.keys(prompts).map((name) => el("option", {}, { value: name, textContent: name })));
|
||||
select.value = chosen && prompts[chosen] !== undefined ? chosen : "";
|
||||
};
|
||||
const load = async () => { prompts = await (await api.fetchApi("/promptforge/prompts")).json(); refresh(); };
|
||||
const store = async (name) => { prompts = await (await api.fetchApi("/promptforge/prompts", { method: "POST", body: JSON.stringify({ name, text: text.value }) })).json(); refresh(name); };
|
||||
select.addEventListener("change", () => { if (prompts[select.value] !== undefined) { text.value = prompts[select.value]; node.setDirtyCanvas(true, true); } });
|
||||
previous.addEventListener("click", () => { const names = Object.keys(prompts); if (!names.length) return; const at = (names.indexOf(select.value) - 1 + names.length) % names.length; refresh(names[at]); text.value = prompts[names[at]]; node.setDirtyCanvas(true, true); });
|
||||
next.addEventListener("click", () => { const names = Object.keys(prompts); if (!names.length) return; const at = (names.indexOf(select.value) + 1) % names.length; refresh(names[at]); text.value = prompts[names[at]]; node.setDirtyCanvas(true, true); });
|
||||
save.addEventListener("click", () => { const name = select.value || window.prompt("Name of this prompt:"); if (name?.trim()) store(name.trim()); });
|
||||
saveAs.addEventListener("click", () => { const name = window.prompt("Name of this prompt:", select.value); if (name?.trim()) store(name.trim()); });
|
||||
remove.addEventListener("click", async () => {
|
||||
if (!select.value || !window.confirm(`Delete the prompt "${select.value}"?`)) return;
|
||||
prompts = await (await api.fetchApi("/promptforge/prompts?name=" + encodeURIComponent(select.value), { method: "DELETE" })).json();
|
||||
refresh("");
|
||||
});
|
||||
const widget = domWidget(node, "saved_prompts", bar, () => 30);
|
||||
node.widgets.splice(node.widgets.indexOf(widget), 1);
|
||||
node.widgets.splice(node.widgets.indexOf(text), 0, widget);
|
||||
load();
|
||||
node.setSize([Math.max(node.size[0], 520), Math.max(node.size[1], node.computeSize()[1])]);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodeData.name !== PARTS) return;
|
||||
const onCreated = nodeType.prototype.onNodeCreated;
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
|
||||
Reference in New Issue
Block a user