View parsed A1111 prompt info
This commit is contained in:
@@ -65,6 +65,7 @@
|
|||||||
"@litegraph-ts/tsconfig": "workspace:*",
|
"@litegraph-ts/tsconfig": "workspace:*",
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
||||||
"@tsconfig/svelte": "^4.0.1",
|
"@tsconfig/svelte": "^4.0.1",
|
||||||
|
"@zerodevx/svelte-json-view": "^1.0.5",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"framework7": "^8.0.3",
|
"framework7": "^8.0.3",
|
||||||
"framework7-svelte": "^8.0.3",
|
"framework7-svelte": "^8.0.3",
|
||||||
|
|||||||
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -73,6 +73,9 @@ importers:
|
|||||||
'@tsconfig/svelte':
|
'@tsconfig/svelte':
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
version: 4.0.1
|
version: 4.0.1
|
||||||
|
'@zerodevx/svelte-json-view':
|
||||||
|
specifier: ^1.0.5
|
||||||
|
version: 1.0.5(svelte@3.58.0)
|
||||||
events:
|
events:
|
||||||
specifier: ^3.3.0
|
specifier: ^3.3.0
|
||||||
version: 3.3.0
|
version: 3.3.0
|
||||||
@@ -3375,6 +3378,14 @@ packages:
|
|||||||
pretty-format: 27.5.1
|
pretty-format: 27.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@zerodevx/svelte-json-view@1.0.5(svelte@3.58.0):
|
||||||
|
resolution: {integrity: sha512-oQDI9v0dJEte6PYVDVjLOjU58AOoWLYRXjghKggFpZXrglWJJqoMeDe14Jrd0cs6NPcPogT/aR/LtkuW2Z1GkQ==}
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^3.55.1
|
||||||
|
dependencies:
|
||||||
|
svelte: 3.58.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@zerodevx/svelte-toast@0.9.3(svelte@3.58.0):
|
/@zerodevx/svelte-toast@0.9.3(svelte@3.58.0):
|
||||||
resolution: {integrity: sha512-VPKWR4A9y01fyXRscu9HiTj7tV2hFrpRKZvGwMmaPXfHIXR1D9+NNsz0HXcQ7qZ0C5UaHS3n9uNtPtIcAXT7RQ==}
|
resolution: {integrity: sha512-VPKWR4A9y01fyXRscu9HiTj7tV2hFrpRKZvGwMmaPXfHIXR1D9+NNsz0HXcQ7qZ0C5UaHS3n9uNtPtIcAXT7RQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const GroupKSampler = z.object({
|
|||||||
steps: z.number(),
|
steps: z.number(),
|
||||||
sampler_name: z.string(),
|
sampler_name: z.string(),
|
||||||
scheduler: z.string(),
|
scheduler: z.string(),
|
||||||
denoise: z.number().default(1.0)
|
denoise: z.number().default(1.0),
|
||||||
type: z.enum(["empty", "image", "upscale"]).optional()
|
type: z.enum(["empty", "image", "upscale"]).optional()
|
||||||
})
|
})
|
||||||
export type ComfyBoxStdGroupKSampler = z.infer<typeof GroupKSampler>
|
export type ComfyBoxStdGroupKSampler = z.infer<typeof GroupKSampler>
|
||||||
@@ -62,6 +62,12 @@ const GroupSDUpscale = z.object({
|
|||||||
})
|
})
|
||||||
export type ComfyBoxStdGroupSDUpscale = z.infer<typeof GroupSDUpscale>
|
export type ComfyBoxStdGroupSDUpscale = z.infer<typeof GroupSDUpscale>
|
||||||
|
|
||||||
|
const GroupSelfAttentionGuidance = z.object({
|
||||||
|
guidance_scale: z.number(),
|
||||||
|
mask_threshold: z.number(),
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupSelfAttentionGuidance = z.infer<typeof GroupSelfAttentionGuidance>
|
||||||
|
|
||||||
const GroupHypernetwork = z.object({
|
const GroupHypernetwork = z.object({
|
||||||
model_name: z.string(),
|
model_name: z.string(),
|
||||||
model_hashes: ModelHashes.optional(),
|
model_hashes: ModelHashes.optional(),
|
||||||
@@ -102,7 +108,7 @@ const GroupDynamicThresholding = z.object({
|
|||||||
mimic_scale: z.number(),
|
mimic_scale: z.number(),
|
||||||
threshold_percentile: z.number(),
|
threshold_percentile: z.number(),
|
||||||
mimic_mode: z.string(),
|
mimic_mode: z.string(),
|
||||||
mimic_scale_min: z.number(),
|
mimic_scale_minimum: z.number(),
|
||||||
cfg_mode: z.string(),
|
cfg_mode: z.string(),
|
||||||
cfg_scale_minimum: z.number()
|
cfg_scale_minimum: z.number()
|
||||||
})
|
})
|
||||||
@@ -120,6 +126,23 @@ const GroupAestheticEmbedding = z.object({
|
|||||||
})
|
})
|
||||||
export type ComfyBoxStdGroupAestheticEmbedding = z.infer<typeof GroupAestheticEmbedding>
|
export type ComfyBoxStdGroupAestheticEmbedding = z.infer<typeof GroupAestheticEmbedding>
|
||||||
|
|
||||||
|
const GroupDDetailer = z.object({
|
||||||
|
positive_prompt: z.string(),
|
||||||
|
negative_prompt: z.string(),
|
||||||
|
bitwise: z.string(),
|
||||||
|
model: z.string().optional(),
|
||||||
|
model_hashes: ModelHashes.optional(),
|
||||||
|
conf: z.number(),
|
||||||
|
mask_blur: z.number(),
|
||||||
|
denoise: z.number(),
|
||||||
|
dilation: z.number(),
|
||||||
|
offset_x: z.number(),
|
||||||
|
offset_y: z.number(),
|
||||||
|
inpaint_full: z.number(),
|
||||||
|
inpaint_padding: z.number(),
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupDDetailer = z.infer<typeof GroupDDetailer>
|
||||||
|
|
||||||
const group = (s: ZodTypeAny) => z.optional(z.array(s).nonempty());
|
const group = (s: ZodTypeAny) => z.optional(z.array(s).nonempty());
|
||||||
|
|
||||||
const Parameters = z.object({
|
const Parameters = z.object({
|
||||||
@@ -133,7 +156,9 @@ const Parameters = z.object({
|
|||||||
hypernetwork: group(GroupHypernetwork),
|
hypernetwork: group(GroupHypernetwork),
|
||||||
lora: group(GroupLoRA),
|
lora: group(GroupLoRA),
|
||||||
control_net: group(GroupControlNet),
|
control_net: group(GroupControlNet),
|
||||||
dynamic_thresholding: group(GroupDynamicThresholding)
|
dynamic_thresholding: group(GroupDynamicThresholding),
|
||||||
|
self_attention_guidance: group(GroupSelfAttentionGuidance),
|
||||||
|
ddetailer: group(GroupDDetailer)
|
||||||
}).partial()
|
}).partial()
|
||||||
export type ComfyBoxStdParameters = z.infer<typeof Parameters>
|
export type ComfyBoxStdParameters = z.infer<typeof Parameters>
|
||||||
|
|
||||||
@@ -141,14 +166,19 @@ const ComfyBoxExtraData = z.object({
|
|||||||
workflows: z.array(z.string())
|
workflows: z.array(z.string())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const A1111ExtraData = z.object({
|
||||||
|
params: z.any()
|
||||||
|
})
|
||||||
|
|
||||||
const ExtraData = z.object({
|
const ExtraData = z.object({
|
||||||
comfybox: ComfyBoxExtraData.optional()
|
comfybox: ComfyBoxExtraData.optional(),
|
||||||
|
a1111: A1111ExtraData.optional()
|
||||||
})
|
})
|
||||||
|
|
||||||
const Metadata = z.object({
|
const Metadata = z.object({
|
||||||
version: z.number(),
|
|
||||||
created_with: z.string(),
|
created_with: z.string(),
|
||||||
author: z.string().optional(),
|
author: z.string().optional(),
|
||||||
|
app_version: z.string().optional(),
|
||||||
commit_hash: z.string().optional(),
|
commit_hash: z.string().optional(),
|
||||||
extra_data: ExtraData
|
extra_data: ExtraData
|
||||||
})
|
})
|
||||||
@@ -159,6 +189,7 @@ const Prompt = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const ComfyBoxStdPrompt = z.object({
|
const ComfyBoxStdPrompt = z.object({
|
||||||
|
version: z.number(),
|
||||||
prompt: Prompt,
|
prompt: Prompt,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
114
src/lib/components/A1111PromptDisplay.svelte
Normal file
114
src/lib/components/A1111PromptDisplay.svelte
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import ComfyBoxStdPrompt from "$lib/ComfyBoxStdPrompt";
|
||||||
|
import type { A1111ParsedInfotext } from "$lib/parseA1111";
|
||||||
|
import { Block, BlockTitle } from "@gradio/atoms";
|
||||||
|
import { TextBox } from "@gradio/form";
|
||||||
|
import { JsonView } from '@zerodevx/svelte-json-view'
|
||||||
|
import type { A1111PromptAndInfo } from "./ComfyApp";
|
||||||
|
import { StaticImage } from "./gradio/image";
|
||||||
|
|
||||||
|
export let prompt: A1111PromptAndInfo | null = null;
|
||||||
|
|
||||||
|
let json: any = {}
|
||||||
|
let a1111: A1111ParsedInfotext | null = null
|
||||||
|
let infotext: string = ""
|
||||||
|
let image: string | null = null;
|
||||||
|
|
||||||
|
$: if (prompt) {
|
||||||
|
infotext = prompt.infotext;
|
||||||
|
a1111 = prompt.parsedInfotext;
|
||||||
|
json = prompt.stdPrompt;
|
||||||
|
image = URL.createObjectURL(prompt.imageFile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
infotext = ""
|
||||||
|
a1111 = null;
|
||||||
|
json = {}
|
||||||
|
image = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if prompt != null}
|
||||||
|
<div class="a1111-prompt-display">
|
||||||
|
<div class="prompt-container">
|
||||||
|
<Block>
|
||||||
|
<TextBox label="Infotext" show_label={true} value={infotext} lines={5} max_lines={20}/>
|
||||||
|
</Block>
|
||||||
|
<div class="scroll-container">
|
||||||
|
{#if a1111}
|
||||||
|
{#if Object.keys(a1111.extraParams).length > 0}
|
||||||
|
<Block>
|
||||||
|
<BlockTitle>Unused Parameters</BlockTitle>
|
||||||
|
<div class="json">
|
||||||
|
<JsonView json={a1111.extraParams} />
|
||||||
|
</div>
|
||||||
|
</Block>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
<Block>
|
||||||
|
<BlockTitle>Converted Prompt</BlockTitle>
|
||||||
|
<div class="json">
|
||||||
|
<JsonView {json} />
|
||||||
|
</div>
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Block>
|
||||||
|
<StaticImage show_label={false} label="Image" value={image} />
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.a1111-prompt-display {
|
||||||
|
width: 70vw;
|
||||||
|
height: 70vh;
|
||||||
|
color: none;
|
||||||
|
|
||||||
|
--jsonPaddingLeft: 1rem;
|
||||||
|
--jsonBorderLeft: 1px dotted var(--neutral-600);
|
||||||
|
--jsonBracketColor: currentcolor;
|
||||||
|
--jsonBracketHoverBackground: var(--neutral-100);
|
||||||
|
--jsonSeparatorColor: currentcolor;
|
||||||
|
--jsonKeyColor: var(--body-text-color);
|
||||||
|
--jsonValColor: var(--body-text-color-subdued);
|
||||||
|
--jsonValStringColor: var(--color-green-500);
|
||||||
|
--jsonValNumberColor: var(--color-blue-500);
|
||||||
|
--jsonValBooleanColor: var(--color-red-500);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
overflow-y: none;
|
||||||
|
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.prompt-container {
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.json {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
position: relative;
|
||||||
|
flex: 1 1 0%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(> .block) {
|
||||||
|
background: var(--panel-background-fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
background: var(--panel-background-fill);
|
||||||
|
|
||||||
|
|
||||||
|
:global(> .block .block) {
|
||||||
|
background: var(--panel-background-fill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,13 +5,12 @@
|
|||||||
import { Button } from "@gradio/button";
|
import { Button } from "@gradio/button";
|
||||||
import { BlockTitle } from "@gradio/atoms";
|
import { BlockTitle } from "@gradio/atoms";
|
||||||
import ComfyUIPane from "./ComfyUIPane.svelte";
|
import ComfyUIPane from "./ComfyUIPane.svelte";
|
||||||
import ComfyApp, { type SerializedAppState } from "./ComfyApp";
|
import ComfyApp, { type A1111PromptAndInfo, type SerializedAppState } from "./ComfyApp";
|
||||||
import { Checkbox, TextBox } from "@gradio/form"
|
import { Checkbox, TextBox } from "@gradio/form"
|
||||||
import uiState from "$lib/stores/uiState";
|
import uiState from "$lib/stores/uiState";
|
||||||
import layoutState from "$lib/stores/layoutState";
|
import layoutState from "$lib/stores/layoutState";
|
||||||
import selectionState from "$lib/stores/selectionState";
|
import selectionState from "$lib/stores/selectionState";
|
||||||
import { ImageViewer } from "$lib/ImageViewer";
|
import { ImageViewer } from "$lib/ImageViewer";
|
||||||
import type { ComfyAPIStatus } from "$lib/api";
|
|
||||||
import { SvelteToast, toast } from '@zerodevx/svelte-toast'
|
import { SvelteToast, toast } from '@zerodevx/svelte-toast'
|
||||||
|
|
||||||
import { LGraph } from "@litegraph-ts/core";
|
import { LGraph } from "@litegraph-ts/core";
|
||||||
@@ -23,11 +22,15 @@
|
|||||||
import ComfyGraphView from "./ComfyGraphView.svelte";
|
import ComfyGraphView from "./ComfyGraphView.svelte";
|
||||||
import { download, jsonToJsObject } from "$lib/utils";
|
import { download, jsonToJsObject } from "$lib/utils";
|
||||||
import notify from "$lib/notify";
|
import notify from "$lib/notify";
|
||||||
|
import Modal from "./Modal.svelte";
|
||||||
|
import ComfyBoxStdPrompt from "$lib/ComfyBoxStdPrompt";
|
||||||
|
import A1111PromptDisplay from "./A1111PromptDisplay.svelte";
|
||||||
|
import type { A1111ParsedInfotext } from "$lib/parseA1111";
|
||||||
|
|
||||||
export let app: ComfyApp = undefined;
|
export let app: ComfyApp = undefined;
|
||||||
let queue: ComfyQueue = undefined;
|
let alreadySetup: Writable<boolean> = writable(false);
|
||||||
|
let a1111Prompt: Writable<A1111PromptAndInfo | null> = writable(null);
|
||||||
let mainElem: HTMLDivElement;
|
let mainElem: HTMLDivElement;
|
||||||
let uiPane: ComfyUIPane = undefined;
|
|
||||||
let props: ComfyProperties = undefined;
|
let props: ComfyProperties = undefined;
|
||||||
let containerElem: HTMLDivElement;
|
let containerElem: HTMLDivElement;
|
||||||
let resizeTimeout: NodeJS.Timeout | null;
|
let resizeTimeout: NodeJS.Timeout | null;
|
||||||
@@ -44,6 +47,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if(app) {
|
||||||
|
alreadySetup = app.alreadySetup;
|
||||||
|
a1111Prompt = app.a1111Prompt;
|
||||||
|
}
|
||||||
|
|
||||||
function refreshView(event?: Event) {
|
function refreshView(event?: Event) {
|
||||||
clearTimeout(resizeTimeout);
|
clearTimeout(resizeTimeout);
|
||||||
resizeTimeout = setTimeout(app.resizeCanvas.bind(app), 250);
|
resizeTimeout = setTimeout(app.resizeCanvas.bind(app), 250);
|
||||||
@@ -188,6 +196,10 @@
|
|||||||
else {
|
else {
|
||||||
document.getElementById("app-root").classList.remove("dark")
|
document.getElementById("app-root").classList.remove("dark")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let showModal: boolean = false;
|
||||||
|
|
||||||
|
$: showModal = $a1111Prompt != null
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@@ -196,8 +208,19 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<Modal bind:showModal on:close={() => ($a1111Prompt = null)}>
|
||||||
|
<div slot="header" class="prompt-modal-header">
|
||||||
|
<h1 style="padding-bottom: 1rem;">A1111 Prompt Details</h1>
|
||||||
|
</div>
|
||||||
|
<A1111PromptDisplay prompt={$a1111Prompt} />
|
||||||
|
<div slot="buttons" let:closeDialog>
|
||||||
|
<Button variant="secondary" on:click={closeDialog}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div id="main" class:dark={uiTheme === "gradio-dark"}>
|
<div id="main" class:dark={uiTheme === "gradio-dark"}>
|
||||||
<div id="dropzone" class="dropzone"></div>
|
|
||||||
<div id="container" bind:this={containerElem}>
|
<div id="container" bind:this={containerElem}>
|
||||||
<Splitpanes theme="comfy" on:resize={refreshView}>
|
<Splitpanes theme="comfy" on:resize={refreshView}>
|
||||||
<Pane bind:size={propsSidebarSize}>
|
<Pane bind:size={propsSidebarSize}>
|
||||||
@@ -208,7 +231,7 @@
|
|||||||
<Pane>
|
<Pane>
|
||||||
<Splitpanes theme="comfy" on:resize={refreshView} horizontal="{true}">
|
<Splitpanes theme="comfy" on:resize={refreshView} horizontal="{true}">
|
||||||
<Pane>
|
<Pane>
|
||||||
<ComfyUIPane bind:this={uiPane} {app} />
|
<ComfyUIPane {app} />
|
||||||
</Pane>
|
</Pane>
|
||||||
<Pane bind:size={graphSize}>
|
<Pane bind:size={graphSize}>
|
||||||
<ComfyGraphView {app} transitioning={graphTransitioning} />
|
<ComfyGraphView {app} transitioning={graphTransitioning} />
|
||||||
@@ -217,7 +240,7 @@
|
|||||||
</Pane>
|
</Pane>
|
||||||
<Pane bind:size={queueSidebarSize}>
|
<Pane bind:size={queueSidebarSize}>
|
||||||
<div class="sidebar-wrapper pane-wrapper">
|
<div class="sidebar-wrapper pane-wrapper">
|
||||||
<ComfyQueue bind:this={queue} />
|
<ComfyQueue />
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</Pane>
|
||||||
</Splitpanes>
|
</Splitpanes>
|
||||||
@@ -225,35 +248,35 @@
|
|||||||
<div id="bottombar">
|
<div id="bottombar">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
{#if $layoutState.attrs.queuePromptButtonName != ""}
|
{#if $layoutState.attrs.queuePromptButtonName != ""}
|
||||||
<Button variant="primary" on:click={queuePrompt}>
|
<Button variant="primary" disabled={!$alreadySetup} on:click={queuePrompt}>
|
||||||
{$layoutState.attrs.queuePromptButtonName}
|
{$layoutState.attrs.queuePromptButtonName}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
<Button variant="secondary" on:click={toggleGraph}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={toggleGraph}>
|
||||||
Toggle Graph
|
Toggle Graph
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={toggleProps}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={toggleProps}>
|
||||||
Toggle Props
|
Toggle Props
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={toggleQueue}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={toggleQueue}>
|
||||||
Toggle Queue
|
Toggle Queue
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doSave}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doSave}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doSaveLocal}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doSaveLocal}>
|
||||||
Save Local
|
Save Local
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doLoad}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doLoad}>
|
||||||
Load
|
Load
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doClear}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doClear}>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doLoadDefault}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doLoadDefault}>
|
||||||
Load Default
|
Load Default
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="secondary" on:click={doRefreshCombos}>
|
<Button variant="secondary" disabled={!$alreadySetup} on:click={doRefreshCombos}>
|
||||||
🔄
|
🔄
|
||||||
</Button>
|
</Button>
|
||||||
<!-- <Checkbox label="Lock Nodes" bind:value={$uiState.nodesLocked}/>
|
<!-- <Checkbox label="Lock Nodes" bind:value={$uiState.nodesLocked}/>
|
||||||
@@ -325,19 +348,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropzone {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 99999;
|
|
||||||
background: #60a7dc80;
|
|
||||||
border: 4px dashed #60a7dc;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(html, body) {
|
:global(html, body) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import layoutState from "$lib/stores/layoutState";
|
|||||||
import { toast } from '@zerodevx/svelte-toast'
|
import { toast } from '@zerodevx/svelte-toast'
|
||||||
import ComfyGraph from "$lib/ComfyGraph";
|
import ComfyGraph from "$lib/ComfyGraph";
|
||||||
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||||
import { get } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import uiState from "$lib/stores/uiState";
|
import uiState from "$lib/stores/uiState";
|
||||||
import { download, graphToGraphVis, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
import { download, graphToGraphVis, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
||||||
@@ -37,6 +37,9 @@ import type { ComfyExecutionResult } from "$lib/utils";
|
|||||||
import ComfyPromptSerializer, { UpstreamNodeLocator, isActiveBackendNode } from "./ComfyPromptSerializer";
|
import ComfyPromptSerializer, { UpstreamNodeLocator, isActiveBackendNode } from "./ComfyPromptSerializer";
|
||||||
import { iterateNodeDefInputs, type ComfyNodeDef, isBackendNodeDefInputType, iterateNodeDefOutputs } from "$lib/ComfyNodeDef";
|
import { iterateNodeDefInputs, type ComfyNodeDef, isBackendNodeDefInputType, iterateNodeDefOutputs } from "$lib/ComfyNodeDef";
|
||||||
import { ComfyComboNode } from "$lib/nodes/widgets";
|
import { ComfyComboNode } from "$lib/nodes/widgets";
|
||||||
|
import parseA1111, { type A1111ParsedInfotext } from "$lib/parseA1111";
|
||||||
|
import convertA1111ToStdPrompt from "$lib/convertA1111ToStdPrompt";
|
||||||
|
import type { ComfyBoxStdPrompt } from "$lib/ComfyBoxStdPrompt";
|
||||||
|
|
||||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||||
|
|
||||||
@@ -55,6 +58,13 @@ type QueueItem = {
|
|||||||
batchCount: number
|
batchCount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type A1111PromptAndInfo = {
|
||||||
|
infotext: string,
|
||||||
|
parsedInfotext: A1111ParsedInfotext,
|
||||||
|
stdPrompt: ComfyBoxStdPrompt,
|
||||||
|
imageFile: File
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Represents a single workflow that can be loaded into the program from JSON.
|
* Represents a single workflow that can be loaded into the program from JSON.
|
||||||
*/
|
*/
|
||||||
@@ -128,10 +138,11 @@ export default class ComfyApp {
|
|||||||
shiftDown: boolean = false;
|
shiftDown: boolean = false;
|
||||||
ctrlDown: boolean = false;
|
ctrlDown: boolean = false;
|
||||||
selectedGroupMoving: boolean = false;
|
selectedGroupMoving: boolean = false;
|
||||||
|
alreadySetup: Writable<boolean> = writable(false);
|
||||||
|
a1111Prompt: Writable<A1111PromptAndInfo | null> = writable(null);
|
||||||
|
|
||||||
private queueItems: QueueItem[] = [];
|
private queueItems: QueueItem[] = [];
|
||||||
private processingQueue: boolean = false;
|
private processingQueue: boolean = false;
|
||||||
private alreadySetup = false;
|
|
||||||
private promptSerializer: ComfyPromptSerializer;
|
private promptSerializer: ComfyPromptSerializer;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -140,7 +151,7 @@ export default class ComfyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setup(): Promise<void> {
|
async setup(): Promise<void> {
|
||||||
if (this.alreadySetup) {
|
if (get(this.alreadySetup)) {
|
||||||
console.error("Already setup")
|
console.error("Already setup")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -183,7 +194,6 @@ export default class ComfyApp {
|
|||||||
// setInterval(this.saveStateToLocalStorage.bind(this), 1000);
|
// setInterval(this.saveStateToLocalStorage.bind(this), 1000);
|
||||||
|
|
||||||
this.addApiUpdateHandlers();
|
this.addApiUpdateHandlers();
|
||||||
this.addDropHandler();
|
|
||||||
this.addPasteHandler();
|
this.addPasteHandler();
|
||||||
this.addKeyboardHandler();
|
this.addKeyboardHandler();
|
||||||
|
|
||||||
@@ -197,7 +207,7 @@ export default class ComfyApp {
|
|||||||
|
|
||||||
this.requestPermissions();
|
this.requestPermissions();
|
||||||
|
|
||||||
this.alreadySetup = true;
|
this.alreadySetup.set(true);
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -318,70 +328,28 @@ export default class ComfyApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private showDropZone() {
|
|
||||||
if (this.dropZone)
|
|
||||||
this.dropZone.style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideDropZone() {
|
|
||||||
if (this.dropZone)
|
|
||||||
this.dropZone.style.display = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
private allowDrag(event: DragEvent) {
|
|
||||||
if (event.dataTransfer.items?.length > 0) {
|
|
||||||
event.dataTransfer.dropEffect = 'copy';
|
|
||||||
this.showDropZone();
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async handleDrop(event: DragEvent) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.hideDropZone();
|
|
||||||
|
|
||||||
if (event.dataTransfer.files.length > 0) {
|
|
||||||
await this.handleFile(event.dataTransfer.files[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private addDropHandler() {
|
|
||||||
// this.dropZone = document.getElementById("dropzone");
|
|
||||||
|
|
||||||
// if (this.dropZone) {
|
|
||||||
// window.addEventListener('dragenter', this.allowDrag.bind(this));
|
|
||||||
// this.dropZone.addEventListener('dragover', this.allowDrag.bind(this));
|
|
||||||
// this.dropZone.addEventListener('dragleave', this.hideDropZone.bind(this));
|
|
||||||
// this.dropZone.addEventListener('drop', this.handleDrop.bind(this));
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// console.warn("No dropzone detected (probably on mobile).")
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a handler on paste that extracts and loads workflows from pasted JSON data
|
* Adds a handler on paste that extracts and loads workflows from pasted JSON data
|
||||||
*/
|
*/
|
||||||
private addPasteHandler() {
|
private addPasteHandler() {
|
||||||
// document.addEventListener("paste", (e) => {
|
document.addEventListener("paste", (e) => {
|
||||||
// let data = (e.clipboardData || (window as any).clipboardData).getData("text/plain");
|
let data = (e.clipboardData || (window as any).clipboardData).getData("text/plain");
|
||||||
// let workflow;
|
let workflow;
|
||||||
// try {
|
try {
|
||||||
// data = data.slice(data.indexOf("{"));
|
data = data.slice(data.indexOf("{"));
|
||||||
// workflow = JSON.parse(data);
|
workflow = JSON.parse(data);
|
||||||
// } catch (err) {
|
} catch (err) {
|
||||||
// try {
|
try {
|
||||||
// data = data.slice(data.indexOf("workflow\n"));
|
data = data.slice(data.indexOf("workflow\n"));
|
||||||
// data = data.slice(data.indexOf("{"));
|
data = data.slice(data.indexOf("{"));
|
||||||
// workflow = JSON.parse(data);
|
workflow = JSON.parse(data);
|
||||||
// } catch (error) { }
|
} catch (error) { }
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (workflow && workflow.version && workflow.nodes && workflow.extra) {
|
if (workflow && workflow.version && workflow.nodes && workflow.extra) {
|
||||||
// this.loadGraphData(workflow);
|
this.loadGraphData(workflow);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -745,8 +713,18 @@ export default class ComfyApp {
|
|||||||
if (pngInfo.comfyBoxConfig) {
|
if (pngInfo.comfyBoxConfig) {
|
||||||
this.deserialize(JSON.parse(pngInfo.comfyBoxConfig));
|
this.deserialize(JSON.parse(pngInfo.comfyBoxConfig));
|
||||||
} else if (pngInfo.parameters) {
|
} else if (pngInfo.parameters) {
|
||||||
throw "TODO A111 import!"
|
const parsed = parseA1111(pngInfo.parameters)
|
||||||
// importA1111(this.lGraph, pngInfo.parameters, this.api);
|
if ("error" in parsed) {
|
||||||
|
notify(`Couldn't parse webui prompt: ${parsed.error}`, { type: "error" })
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const converted = convertA1111ToStdPrompt(parsed)
|
||||||
|
this.a1111Prompt.set({
|
||||||
|
infotext: pngInfo.parameters,
|
||||||
|
parsedInfotext: parsed,
|
||||||
|
stdPrompt: converted,
|
||||||
|
imageFile: file
|
||||||
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.error("No metadata found in image file.", pngInfo)
|
console.error("No metadata found in image file.", pngInfo)
|
||||||
@@ -890,5 +868,6 @@ export default class ComfyApp {
|
|||||||
*/
|
*/
|
||||||
clean() {
|
clean() {
|
||||||
this.nodeOutputs = {};
|
this.nodeOutputs = {};
|
||||||
|
this.a1111Prompt.set(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import layoutState, { type ContainerLayout, type DragItem, type IDragItem } from "$lib/stores/layoutState";
|
import layoutState, { type ContainerLayout, type DragItem, type IDragItem } from "$lib/stores/layoutState";
|
||||||
import uiState from "$lib/stores/uiState";
|
import uiState from "$lib/stores/uiState";
|
||||||
import selectionState from "$lib/stores/selectionState";
|
import selectionState from "$lib/stores/selectionState";
|
||||||
|
import DropZone from "./DropZone.svelte";
|
||||||
|
|
||||||
import Menu from './menu/Menu.svelte';
|
import Menu from './menu/Menu.svelte';
|
||||||
import MenuOption from './menu/MenuOption.svelte';
|
import MenuOption from './menu/MenuOption.svelte';
|
||||||
@@ -150,6 +151,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="comfy-ui-panes" on:contextmenu={onRightClick}>
|
<div id="comfy-ui-panes" on:contextmenu={onRightClick}>
|
||||||
|
<DropZone {app} />
|
||||||
<WidgetContainer bind:dragItem={root} classes={["root-container"]} />
|
<WidgetContainer bind:dragItem={root} classes={["root-container"]} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
78
src/lib/components/DropZone.svelte
Normal file
78
src/lib/components/DropZone.svelte
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import type ComfyApp from "./ComfyApp";
|
||||||
|
|
||||||
|
export let app: ComfyApp;
|
||||||
|
let a1111Prompt: Writable<any | null> = writable(null);
|
||||||
|
let dropZone: HTMLDivElement | null = null;
|
||||||
|
let disabled = false;
|
||||||
|
|
||||||
|
$: a1111Prompt = app.a1111Prompt;
|
||||||
|
|
||||||
|
$: disabled = a1111Prompt && $a1111Prompt;
|
||||||
|
|
||||||
|
$: if (disabled) {
|
||||||
|
hideDropZone();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDropZone() {
|
||||||
|
if (dropZone && !disabled)
|
||||||
|
dropZone.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideDropZone() {
|
||||||
|
if (dropZone)
|
||||||
|
dropZone.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowDrag(event: DragEvent) {
|
||||||
|
if (disabled)
|
||||||
|
return
|
||||||
|
|
||||||
|
if (event.dataTransfer != null && event.dataTransfer.items?.length > 0) {
|
||||||
|
event.dataTransfer.dropEffect = 'copy';
|
||||||
|
showDropZone();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDrop(event: DragEvent) {
|
||||||
|
if (disabled)
|
||||||
|
return
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
hideDropZone();
|
||||||
|
|
||||||
|
if (event.dataTransfer != null && event.dataTransfer.files.length > 0) {
|
||||||
|
await app.handleFile(event.dataTransfer.files[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:dragenter={showDropZone} />
|
||||||
|
|
||||||
|
{#if !disabled}
|
||||||
|
<div id="dropzone"
|
||||||
|
class="dropzone"
|
||||||
|
bind:this={dropZone}
|
||||||
|
on:dragover={allowDrag}
|
||||||
|
on:dragleave={hideDropZone}
|
||||||
|
on:drop={handleDrop}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.dropzone {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 99999;
|
||||||
|
background: #60a7dc80;
|
||||||
|
border: 4px dashed #60a7dc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -94,5 +94,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--spacing-sm);
|
gap: var(--spacing-sm);
|
||||||
|
padding-top: 0.5em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ComfyBoxStdGroupCheckpoint, ComfyBoxStdGroupHypernetwork, ComfyBoxStdGroupKSampler, ComfyBoxStdGroupLatentImage, ComfyBoxStdGroupLoRA, ComfyBoxStdParameters, ComfyBoxStdPrompt } from "./ComfyBoxStdPrompt";
|
import type { ComfyBoxStdGroupCheckpoint, ComfyBoxStdGroupDDetailer, ComfyBoxStdGroupDynamicThresholding, ComfyBoxStdGroupHypernetwork, ComfyBoxStdGroupKSampler, ComfyBoxStdGroupLatentImage, ComfyBoxStdGroupLoRA, ComfyBoxStdGroupSelfAttentionGuidance, ComfyBoxStdParameters, ComfyBoxStdPrompt } from "./ComfyBoxStdPrompt";
|
||||||
import type { A1111ParsedInfotext } from "./parseA1111";
|
import type { A1111ParsedInfotext } from "./parseA1111";
|
||||||
|
|
||||||
function getSamplerAndScheduler(a1111Sampler: string): [string, string] {
|
function getSamplerAndScheduler(a1111Sampler: string): [string, string] {
|
||||||
@@ -14,14 +14,30 @@ function getSamplerAndScheduler(a1111Sampler: string): [string, string] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const reAddNetModelName = /^([^(]+)\(([^)]+)\)$/;
|
const reAddNetModelName = /^([^(]+)\(([^)]+)\)$/;
|
||||||
const reParens = /\(([^)]+)\)/;
|
|
||||||
|
|
||||||
function parseAddNetModelNameAndHash(name: string): [string | null, string | null] {
|
function parseAddNetModelNameAndHash(name: string | null): [string | undefined, string | undefined] {
|
||||||
|
if (!name)
|
||||||
|
return [undefined, undefined]
|
||||||
|
|
||||||
const match = name.match(reAddNetModelName);
|
const match = name.match(reAddNetModelName);
|
||||||
if (match) {
|
if (match) {
|
||||||
return [match[1], match[2]]
|
return [match[1], match[2]]
|
||||||
}
|
}
|
||||||
return [null, null]
|
return [undefined, undefined]
|
||||||
|
}
|
||||||
|
|
||||||
|
const reDDetailerModelName = /(.+)\s\[(.+)\]/;
|
||||||
|
|
||||||
|
function parseDDetailerModelNameAndHash(name: string | null): [string | undefined, string | undefined] {
|
||||||
|
if (!name || name === "None")
|
||||||
|
return [undefined, undefined]
|
||||||
|
|
||||||
|
// bbox\mmdet_anime-face_yolov3.pth [51e1af4a]
|
||||||
|
const match = name.match(reDDetailerModelName);
|
||||||
|
if (match) {
|
||||||
|
return [match[1], match[2]]
|
||||||
|
}
|
||||||
|
return [undefined, undefined]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): ComfyBoxStdPrompt {
|
export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): ComfyBoxStdPrompt {
|
||||||
@@ -49,12 +65,6 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext):
|
|||||||
[hrWidth, hrHeight] = hrSz.split(hrSz).map(parseInt);
|
[hrWidth, hrHeight] = hrSz.split(hrSz).map(parseInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hrMethod != null && hrMethod.startsWith("Latent (")) {
|
|
||||||
const result = reParens.exec(hrMethod)
|
|
||||||
if (result)
|
|
||||||
hrMethod = String(result[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
const latent_image: ComfyBoxStdGroupLatentImage = {
|
const latent_image: ComfyBoxStdGroupLatentImage = {
|
||||||
width: infotext.width,
|
width: infotext.width,
|
||||||
height: infotext.height,
|
height: infotext.height,
|
||||||
@@ -127,15 +137,15 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext):
|
|||||||
parameters.checkpoint = [checkpoint]
|
parameters.checkpoint = [checkpoint]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("clip skip" in infotext.extraParams) {
|
||||||
const clipSkip = popOpt("clip skip")
|
const clipSkip = popOpt("clip skip")
|
||||||
if (clipSkip != null) {
|
|
||||||
parameters.clip = [{
|
parameters.clip = [{
|
||||||
clip_skip: parseInt(clipSkip)
|
clip_skip: parseInt(clipSkip)
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("sd upscale upscaler" in infotext.extraParams) {
|
||||||
const sdUpscaleUpscaler = popOpt("sd upscale upscaler")
|
const sdUpscaleUpscaler = popOpt("sd upscale upscaler")
|
||||||
if (sdUpscaleUpscaler != null) {
|
|
||||||
const sdUpscaleOverlap = popOpt("sd upscale overlap") || "64"
|
const sdUpscaleOverlap = popOpt("sd upscale overlap") || "64"
|
||||||
parameters.sd_upscale = [{
|
parameters.sd_upscale = [{
|
||||||
upscaler: sdUpscaleUpscaler,
|
upscaler: sdUpscaleUpscaler,
|
||||||
@@ -143,6 +153,85 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext):
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("dynamic thresholding enabled" in infotext.extraParams) {
|
||||||
|
const dtEnabled = popOpt("dynamic thresholding enabled")
|
||||||
|
if (dtEnabled === "True") {
|
||||||
|
const dynamic_thresholding: ComfyBoxStdGroupDynamicThresholding = {
|
||||||
|
mimic_scale: parseInt(popOpt("mimic scale")),
|
||||||
|
threshold_percentile: parseFloat(popOpt("threshold percentile")),
|
||||||
|
mimic_mode: popOpt("mimic mode"),
|
||||||
|
mimic_scale_minimum: parseFloat(popOpt("mimic scale minimum")),
|
||||||
|
cfg_mode: popOpt("cfg mode"),
|
||||||
|
cfg_scale_minimum: parseFloat(popOpt("cfg scale minimum")),
|
||||||
|
}
|
||||||
|
parameters.dynamic_thresholding = [dynamic_thresholding]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("sag guidance scale" in infotext.extraParams) {
|
||||||
|
const self_attention_guidance: ComfyBoxStdGroupSelfAttentionGuidance = {
|
||||||
|
guidance_scale: parseFloat(popOpt("sag guidance scale")),
|
||||||
|
mask_threshold: parseFloat(popOpt("sag mask threshold")),
|
||||||
|
}
|
||||||
|
parameters.self_attention_guidance = [self_attention_guidance]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("ddetailer prompt" in infotext.extraParams) {
|
||||||
|
const positive_prompt = popOpt("ddetailer prompt")
|
||||||
|
const negative_prompt = popOpt("ddetailer neg prompt")
|
||||||
|
const bitwise = popOpt("ddetailer bitwise")
|
||||||
|
const denoise = parseFloat(popOpt("ddetailer denoising"))
|
||||||
|
const inpaint_full = popOpt("ddetailer inpaint full") === "True"
|
||||||
|
const inpaint_padding = parseInt(popOpt("ddetailer inpaint padding"))
|
||||||
|
const mask_blur = parseFloat(popOpt("ddetailer mask blur"))
|
||||||
|
const cfg = parseFloat(popOpt("ddetailer cfg"))
|
||||||
|
|
||||||
|
const preprocess_b = popOpt("ddetailer preprocess b") === "True"
|
||||||
|
|
||||||
|
const [model_a, model_a_shorthash] = parseDDetailerModelNameAndHash(popOpt("ddetailer model a"))
|
||||||
|
const [model_b, model_b_shorthash] = parseDDetailerModelNameAndHash(popOpt("ddetailer model b"))
|
||||||
|
|
||||||
|
const ddetailer_a: ComfyBoxStdGroupDDetailer = {
|
||||||
|
positive_prompt,
|
||||||
|
negative_prompt,
|
||||||
|
bitwise,
|
||||||
|
denoise,
|
||||||
|
inpaint_full,
|
||||||
|
inpaint_padding,
|
||||||
|
mask_blur,
|
||||||
|
cfg,
|
||||||
|
model: model_a,
|
||||||
|
model_hashes: model_a_shorthash ? {
|
||||||
|
a1111_shorthash: model_a_shorthash
|
||||||
|
} : undefined,
|
||||||
|
preprocess: !preprocess_b,
|
||||||
|
conf: parseFloat(popOpt("ddetailer conf a")),
|
||||||
|
dilation: parseFloat(popOpt("ddetailer dilation a")),
|
||||||
|
offset_x: parseFloat(popOpt("ddetailer offset x a")),
|
||||||
|
offset_y: parseFloat(popOpt("ddetailer offset y a")),
|
||||||
|
}
|
||||||
|
const ddetailer_b: ComfyBoxStdGroupDDetailer = {
|
||||||
|
positive_prompt,
|
||||||
|
negative_prompt,
|
||||||
|
bitwise,
|
||||||
|
denoise,
|
||||||
|
inpaint_full,
|
||||||
|
inpaint_padding,
|
||||||
|
mask_blur,
|
||||||
|
cfg,
|
||||||
|
model: model_b,
|
||||||
|
model_hashes: model_b_shorthash ? {
|
||||||
|
a1111_shorthash: model_b_shorthash
|
||||||
|
} : undefined,
|
||||||
|
preprocess: preprocess_b,
|
||||||
|
conf: parseFloat(popOpt("ddetailer conf b")),
|
||||||
|
dilation: parseFloat(popOpt("ddetailer dilation b")),
|
||||||
|
offset_x: parseFloat(popOpt("ddetailer offset x b")),
|
||||||
|
offset_y: parseFloat(popOpt("ddetailer offset y b")),
|
||||||
|
}
|
||||||
|
parameters.ddetailer = [ddetailer_a, ddetailer_b]
|
||||||
|
}
|
||||||
|
|
||||||
// TODO ControlNet
|
// TODO ControlNet
|
||||||
|
|
||||||
for (const [extraNetworkType, extraNetworks] of Object.entries(infotext.extraNetworks)) {
|
for (const [extraNetworkType, extraNetworks] of Object.entries(infotext.extraNetworks)) {
|
||||||
@@ -150,8 +239,11 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext):
|
|||||||
let strength;
|
let strength;
|
||||||
switch (extraNetworkType.toLowerCase()) {
|
switch (extraNetworkType.toLowerCase()) {
|
||||||
case "lora":
|
case "lora":
|
||||||
|
case "locon":
|
||||||
|
case "lyco":
|
||||||
strength = parseFloat(extraNetworkParams.items[1]);
|
strength = parseFloat(extraNetworkParams.items[1]);
|
||||||
const lora: ComfyBoxStdGroupLoRA = {
|
const lora: ComfyBoxStdGroupLoRA = {
|
||||||
|
module_name: extraNetworkType.toLowerCase(),
|
||||||
model_name: extraNetworkParams.items[0],
|
model_name: extraNetworkParams.items[0],
|
||||||
strength_unet: strength,
|
strength_unet: strength,
|
||||||
strength_tenc: strength,
|
strength_tenc: strength,
|
||||||
@@ -231,12 +323,19 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext):
|
|||||||
found = infotext.extraParams[`addnet model ${index}`]
|
found = infotext.extraParams[`addnet model ${index}`]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let app_version = popOpt("version")
|
||||||
|
|
||||||
const prompt: ComfyBoxStdPrompt = {
|
const prompt: ComfyBoxStdPrompt = {
|
||||||
|
version: 1,
|
||||||
prompt: {
|
prompt: {
|
||||||
metadata: {
|
metadata: {
|
||||||
version: 1,
|
|
||||||
created_with: "stable-diffusion-webui",
|
created_with: "stable-diffusion-webui",
|
||||||
extra_data: {}
|
app_version,
|
||||||
|
extra_data: {
|
||||||
|
a1111: {
|
||||||
|
params: infotext.extraParams
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
parameters
|
parameters
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import convertA1111ToStdPrompt from "$lib/convertA1111ToStdPrompt";
|
|||||||
import { expect } from 'vitest';
|
import { expect } from 'vitest';
|
||||||
import UnitTest from "./UnitTest";
|
import UnitTest from "./UnitTest";
|
||||||
import type { A1111ParsedInfotext } from "$lib/parseA1111";
|
import type { A1111ParsedInfotext } from "$lib/parseA1111";
|
||||||
|
import ComfyBoxStdPrompt from "$lib/ComfyBoxStdPrompt";
|
||||||
|
|
||||||
export default class convertA1111ToStdPromptTests extends UnitTest {
|
export default class convertA1111ToStdPromptTests extends UnitTest {
|
||||||
test__convertsBasic() {
|
test__convertsBasic() {
|
||||||
@@ -32,9 +33,9 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
const converted = convertA1111ToStdPrompt(infotext);
|
const converted = convertA1111ToStdPrompt(infotext);
|
||||||
|
|
||||||
expect(converted).toEqual({
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
prompt: {
|
prompt: {
|
||||||
metadata: {
|
metadata: {
|
||||||
version: 1,
|
|
||||||
created_with: "stable-diffusion-webui",
|
created_with: "stable-diffusion-webui",
|
||||||
extra_data: {}
|
extra_data: {}
|
||||||
},
|
},
|
||||||
@@ -66,6 +67,8 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
test__convertsExtraNetworks() {
|
test__convertsExtraNetworks() {
|
||||||
@@ -101,9 +104,9 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
const converted = convertA1111ToStdPrompt(infotext);
|
const converted = convertA1111ToStdPrompt(infotext);
|
||||||
|
|
||||||
expect(converted).toEqual({
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
prompt: {
|
prompt: {
|
||||||
metadata: {
|
metadata: {
|
||||||
version: 1,
|
|
||||||
created_with: "stable-diffusion-webui",
|
created_with: "stable-diffusion-webui",
|
||||||
extra_data: {}
|
extra_data: {}
|
||||||
},
|
},
|
||||||
@@ -159,6 +162,8 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
test__convertsAdditionalNetworks() {
|
test__convertsAdditionalNetworks() {
|
||||||
@@ -199,9 +204,9 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
const converted = convertA1111ToStdPrompt(infotext)
|
const converted = convertA1111ToStdPrompt(infotext)
|
||||||
|
|
||||||
expect(converted).toEqual({
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
prompt: {
|
prompt: {
|
||||||
metadata: {
|
metadata: {
|
||||||
version: 1,
|
|
||||||
created_with: "stable-diffusion-webui",
|
created_with: "stable-diffusion-webui",
|
||||||
extra_data: {}
|
extra_data: {}
|
||||||
},
|
},
|
||||||
@@ -254,5 +259,7 @@ export default class convertA1111ToStdPromptTests extends UnitTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"paths": {
|
"paths": {
|
||||||
"$lib": ["lib"],
|
"$lib": ["lib"],
|
||||||
|
|||||||
Reference in New Issue
Block a user