Files
by-aeandCursor feb8947b50 Initial release of Ideogram 4 Prompt Builder Pro.
Fork of KJNodes' Ideogram 4 Prompt Builder with stores, multi-select, scene save/load, live background preview, and separate width/height outputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 17:27:52 +10:00

93 lines
2.8 KiB
JavaScript

/** Shared helpers between the enhanced builder nodes. */
import { nodeClassName } from "./utility.js";
const { app } = window.comfyAPI.app;
export const BUILDER_CLASS = "Ideogram4PromptBuilderKJEnhancedByAE";
export const PREVIEW_UPDATE_CLASS = "Ideogram4PromptBuilderKJPreviewUpdateByAE";
const STORE_API = "/byae/ideogram/stores";
const EMPTY_STORES = () => ({ characters: {}, objects: {}, scenes: {} });
export async function loadStores() {
try {
const resp = await fetch(STORE_API);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
return {
characters: data.characters || {},
objects: data.objects || {},
scenes: data.scenes || {},
};
} catch (e) {
console.warn("ByAE Ideogram: failed to load stores", e);
return EMPTY_STORES();
}
}
export async function saveStoreEntry(bucket, name, data) {
const resp = await fetch(`${STORE_API}/${bucket}/${encodeURIComponent(name)}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!resp.ok) {
let msg = `HTTP ${resp.status}`;
try {
const err = await resp.json();
if (err?.error) msg = err.error;
} catch (e) { /* ignore */ }
throw new Error(msg);
}
}
export function findBuildersOnGraph(graph) {
if (!graph?._nodes) return [];
return graph._nodes.filter((n) => nodeClassName(n) === BUILDER_CLASS);
}
let _bgPushListenerInstalled = false;
/** Listen for server push when Preview BG Update writes a temp file. */
export function installBgUpdateListener() {
if (_bgPushListenerInstalled) return;
_bgPushListenerInstalled = true;
const { api } = window.comfyAPI.api;
api.addEventListener("byae_ideogram_bg_updated", ({ detail }) => {
if (!detail?.guid) return;
const graph = app.graph;
if (!graph?._nodes) return;
for (const node of findBuildersOnGraph(graph)) {
const guid = node.properties?.byae_bg_guid;
if (guid && guid === detail.guid) {
node.byaeApplyBgUpdate?.(detail);
}
}
});
}
let _queueHooksInstalled = false;
/** Inject internal editor fields into the workflow prompt (no native backing widgets). */
export function installBuilderQueueHooks() {
if (_queueHooksInstalled) return;
_queueHooksInstalled = true;
const orig = app.graphToPrompt?.bind(app);
if (!orig) return;
app.graphToPrompt = async function (...args) {
const builders = findBuildersOnGraph(app.graph);
for (const n of builders) n.byaePersistState?.();
const res = await orig(...args);
if (!res?.output) return res;
for (const n of builders) {
const patch = n.byaeGetPromptInputs?.();
if (!patch) continue;
const key = String(n.id);
if (!res.output[key]) continue;
res.output[key].inputs = { ...(res.output[key].inputs || {}), ...patch };
}
return res;
};
}