Config default templates
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"comfyUIHostname": "localhost",
|
||||
"comfyUIPort": 8188,
|
||||
"alwaysStripUserState": false,
|
||||
"promptForWorkflowName": false,
|
||||
"confirmWhenUnloadingUnsavedChanges": true
|
||||
"comfyUIHostname": "localhost",
|
||||
"comfyUIPort": 8188,
|
||||
"alwaysStripUserState": false,
|
||||
"promptForWorkflowName": false,
|
||||
"confirmWhenUnloadingUnsavedChanges": true,
|
||||
"builtInTemplates": ["ControlNet", "LoRA x5", "Model Loader", "Positive_Negative", "Seed Randomizer"],
|
||||
"cacheBuiltInResources": true
|
||||
}
|
||||
|
||||
@@ -338,7 +338,6 @@ export function serializeTemplate(canvas: ComfyGraphCanvas, template: ComfyBoxTe
|
||||
uiState.update(s => { s.forceSaveUserState = null; return s; });
|
||||
|
||||
nodes = relocateNodes(nodes);
|
||||
nodes = removeTags(nodes);
|
||||
[nodes, links] = pruneDetachedLinks(nodes, links);
|
||||
|
||||
const svg = renderSvg(canvas, graph, TEMPLATE_SVG_PADDING);
|
||||
@@ -378,29 +377,21 @@ export function extractTemplateJSONFromSVG(svg: string): string | null {
|
||||
/*
|
||||
* Credit goes to pythongosssss for this format
|
||||
*/
|
||||
export function deserializeTemplateFromSVG(file: File): Promise<SerializedComfyBoxTemplate> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
const svg = reader.result as string;
|
||||
let template = null;
|
||||
let templateJSON = extractTemplateJSONFromSVG(svg);
|
||||
if (templateJSON)
|
||||
template = JSON.parse(templateJSON);
|
||||
export function deserializeTemplateFromSVG(svg: string): SerializedComfyBoxTemplate | null {
|
||||
let template = null;
|
||||
let templateJSON = extractTemplateJSONFromSVG(svg);
|
||||
if (templateJSON)
|
||||
template = JSON.parse(templateJSON);
|
||||
|
||||
if (!isSerializedComfyBoxTemplate(template)) {
|
||||
reject("Invalid template format!")
|
||||
}
|
||||
else {
|
||||
template.svg = svg;
|
||||
resolve(template)
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
});
|
||||
if (!isSerializedComfyBoxTemplate(template)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
template.svg = svg;
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function createTemplate(nodes: LGraphNode[]): ComfyBoxTemplateResult {
|
||||
if (nodes.length === 0) {
|
||||
return {
|
||||
|
||||
@@ -29,7 +29,7 @@ import queueState from "$lib/stores/queueState";
|
||||
import selectionState from "$lib/stores/selectionState";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import workflowState, { ComfyBoxWorkflow, type WorkflowAttributes, type WorkflowInstID } from "$lib/stores/workflowState";
|
||||
import type { SerializedPromptOutput } from "$lib/utils";
|
||||
import { readFileToText, type SerializedPromptOutput } from "$lib/utils";
|
||||
import { basename, capitalize, download, graphToGraphVis, jsonToJsObject, promptToGraphVis, range } from "$lib/utils";
|
||||
import { tick } from "svelte";
|
||||
import { type SvelteComponentDev } from "svelte/internal";
|
||||
@@ -264,9 +264,9 @@ export default class ComfyApp {
|
||||
*/
|
||||
async loadConfig() {
|
||||
try {
|
||||
const config = await fetch(`/config.json`);
|
||||
const state = await config.json() as ConfigState;
|
||||
configState.set(state);
|
||||
const config = await fetch(`/config.json`, { cache: "no-store" });
|
||||
const newConfig = await config.json() as ConfigState;
|
||||
configState.set({ ...get(configState), ...newConfig });
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to load config`, error)
|
||||
@@ -274,7 +274,44 @@ export default class ComfyApp {
|
||||
}
|
||||
|
||||
async loadBuiltInTemplates(): Promise<SerializedComfyBoxTemplate[]> {
|
||||
return []
|
||||
const builtInTemplates = get(configState).builtInTemplates
|
||||
const options: RequestInit = get(configState).cacheBuiltInResources ? {} : { cache: "no-store" }
|
||||
const promises = builtInTemplates.map(basename => {
|
||||
return fetch(`/templates/${basename}.svg`, options)
|
||||
.then(res => res.text())
|
||||
.catch(error => error)
|
||||
})
|
||||
|
||||
const [templates, error] = await Promise.all(promises).then((results) => {
|
||||
const templates: SerializedComfyBoxTemplate[] = []
|
||||
const errors: string[] = []
|
||||
|
||||
for (const r of results) {
|
||||
if (r instanceof Error) {
|
||||
errors.push(r.toString())
|
||||
}
|
||||
else {
|
||||
// bare filename of image
|
||||
const svg = r as string;
|
||||
const templateAndSvg = deserializeTemplateFromSVG(svg)
|
||||
if (templateAndSvg == null) {
|
||||
errors.push("Invalid SVG template format")
|
||||
}
|
||||
templates.push(templateAndSvg)
|
||||
}
|
||||
}
|
||||
|
||||
let error = null;
|
||||
if (errors && errors.length > 0)
|
||||
error = "Error(s) loading builtin templates:\n" + errors.join("\n");
|
||||
|
||||
return [templates, error]
|
||||
})
|
||||
|
||||
if (error)
|
||||
notify(error, { type: "error" })
|
||||
|
||||
return templates;
|
||||
}
|
||||
|
||||
resizeCanvas() {
|
||||
@@ -786,7 +823,8 @@ export default class ComfyApp {
|
||||
async initDefaultWorkflow(name: string = "defaultWorkflow", options?: OpenWorkflowOptions) {
|
||||
let state = null;
|
||||
try {
|
||||
const graphResponse = await fetch(`/workflows/${name}.json`);
|
||||
const options: RequestInit = get(configState).cacheBuiltInResources ? {} : { cache: "no-store" }
|
||||
const graphResponse = await fetch(`/workflows/${name}.json`, options);
|
||||
state = await graphResponse.json() as SerializedAppState;
|
||||
}
|
||||
catch (error) {
|
||||
@@ -1061,7 +1099,12 @@ export default class ComfyApp {
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else if (file.type === "image/svg+xml" || file.name.endsWith(".svg")) {
|
||||
const templateAndSvg = await deserializeTemplateFromSVG(file);
|
||||
const svg = await readFileToText(file);
|
||||
const templateAndSvg = deserializeTemplateFromSVG(svg);
|
||||
if (templateAndSvg == null) {
|
||||
notify("Invalid SVG template format!", { type: "error" })
|
||||
return;
|
||||
}
|
||||
|
||||
const importTemplate = () => {
|
||||
try {
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
for (const r of results) {
|
||||
if (r instanceof Error) {
|
||||
errors.push(r.cause)
|
||||
errors.push(r.toString())
|
||||
}
|
||||
else {
|
||||
// bare filename of image
|
||||
|
||||
@@ -17,6 +17,12 @@ export type ConfigState = {
|
||||
|
||||
/** When closing the tab, open the confirmation window if there's unsaved changes */
|
||||
confirmWhenUnloadingUnsavedChanges: boolean,
|
||||
|
||||
/** Basenames of templates that can be loaded from public/templates. Saves LocalStorage space. */
|
||||
builtInTemplates: string[],
|
||||
|
||||
/** Cache loading of built-in resources to save network use */
|
||||
cacheBuiltInResources: boolean
|
||||
}
|
||||
|
||||
type ConfigStateOps = {
|
||||
@@ -30,7 +36,9 @@ const store: Writable<ConfigState> = writable(
|
||||
comfyUIPort: 8188,
|
||||
alwaysStripUserState: false,
|
||||
promptForWorkflowName: false,
|
||||
confirmWhenUnloadingUnsavedChanges: true
|
||||
confirmWhenUnloadingUnsavedChanges: true,
|
||||
builtInTemplates: [],
|
||||
cacheBuiltInResources: true,
|
||||
})
|
||||
|
||||
function getBackendURL(): string {
|
||||
|
||||
@@ -598,3 +598,13 @@ export function calcNodesBoundingBox(nodes: SerializedLGraphNode[]): Vector4 {
|
||||
|
||||
return [min_x, min_y, max_x, max_y];
|
||||
}
|
||||
|
||||
export async function readFileToText(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
resolve(reader.result as string);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user