diff --git a/src/lib/ComfyBoxStdPrompt.ts b/src/lib/ComfyBoxStdPrompt.ts index bbb8b75..61833a0 100644 --- a/src/lib/ComfyBoxStdPrompt.ts +++ b/src/lib/ComfyBoxStdPrompt.ts @@ -1,149 +1,5 @@ import { z, type ZodTypeAny } from "zod" -const ModelHashes = z.object({ - a1111_shorthash: z.string().optional(), - sha256: z.string().optional(), -}).refine(({ a1111_shorthash, sha256 }) => - a1111_shorthash !== undefined || sha256 !== undefined, - { message: "At least one model hash must be specified" }) - -const GroupConditioning = z.object({ - text: z.string(), -}) -export type ComfyBoxStdGroupConditioning = z.infer - -const GroupCheckpoint = z.object({ - model_name: z.string().optional(), - model_hashes: ModelHashes.optional(), -}).refine(({ model_name, model_hashes }) => - model_name !== undefined || model_hashes !== undefined, - { message: "Must include either model name or model hash" } -) -export type ComfyBoxStdGroupCheckpoint = z.infer - -const GroupVAE = z.object({ - model_name: z.string().optional(), - model_hashes: ModelHashes.optional(), - type: z.enum(["internal", "external"]) -}).refine(({ model_name, model_hashes }) => - model_name !== undefined || model_hashes !== undefined, - { message: "Must include either model name or model hashes" } -) -export type ComfyBoxStdGroupVAE = z.infer - -const GroupKSampler = z.object({ - cfg_scale: z.number(), - seed: z.number(), - steps: z.number(), - sampler_name: z.string(), - scheduler: z.string(), - denoise: z.number().default(1.0), - type: z.enum(["empty", "image", "upscale"]).optional() -}) -export type ComfyBoxStdGroupKSampler = z.infer - -const GroupLatentImage = z.object({ - width: z.number(), - height: z.number(), - type: z.enum(["empty", "image", "upscale"]).optional(), - upscale_method: z.string().optional(), - upscale_by: z.number().optional(), - crop: z.string().optional(), - mask_blur: z.number().optional(), - batch_count: z.number().default(1).optional(), - batch_pos: z.number().default(0).optional() -}) -export type ComfyBoxStdGroupLatentImage = z.infer - -const GroupSDUpscale = z.object({ - upscaler: z.string(), - overlap: z.number(), -}) -export type ComfyBoxStdGroupSDUpscale = z.infer - -const GroupSelfAttentionGuidance = z.object({ - guidance_scale: z.number(), - mask_threshold: z.number(), -}) -export type ComfyBoxStdGroupSelfAttentionGuidance = z.infer - -const GroupHypernetwork = z.object({ - model_name: z.string(), - model_hashes: ModelHashes.optional(), - strength: z.number() -}) -export type ComfyBoxStdGroupHypernetwork = z.infer - -const LoRAModelHashes = z.object({ - addnet_shorthash: z.string().optional(), - addnet_shorthash_legacy: z.string().optional(), - sha256: z.string().optional(), -}).refine(({ addnet_shorthash, addnet_shorthash_legacy, sha256 }) => - addnet_shorthash !== undefined || addnet_shorthash_legacy !== undefined || sha256 !== undefined, - { message: "At least one model hash must be specified" }) - -const GroupLoRA = z.object({ - model_name: z.string(), - module_name: z.string().optional(), - model_hashes: LoRAModelHashes.optional(), - strength_unet: z.number(), - strength_tenc: z.number() -}) -export type ComfyBoxStdGroupLoRA = z.infer - -const GroupControlNet = z.object({ - model: z.string(), - model_hashes: ModelHashes.optional(), - strength: z.number(), -}) -export type ComfyBoxStdGroupControlNet = z.infer - -const GroupCLIP = z.object({ - clip_skip: z.number().optional() -}) -export type ComfyBoxStdGroupCLIP = z.infer - -const GroupDynamicThresholding = z.object({ - mimic_scale: z.number(), - threshold_percentile: z.number(), - mimic_mode: z.string(), - mimic_scale_minimum: z.number(), - cfg_mode: z.string(), - cfg_scale_minimum: z.number() -}) -export type ComfyBoxStdGroupDynamicThresholding = z.infer - -const GroupAestheticEmbedding = z.object({ - model_name: z.string(), - lr: z.number(), - slerp: z.boolean(), - slerp_angle: z.number(), - steps: z.number(), - positive: z.string(), - negative: z.string(), - weight: z.number(), -}) -export type ComfyBoxStdGroupAestheticEmbedding = z.infer - -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(), - preprocess: z.boolean(), - inpaint_full: z.boolean(), - inpaint_padding: z.number(), - cfg: z.number() -}) -export type ComfyBoxStdGroupDDetailer = z.infer - /* * This metadata can be attached to each entry in a group to assist in * identifying the correct nodes to apply it to. @@ -170,25 +26,180 @@ const GroupMetadata = z.object({ }) export type ComfyBoxStdGroupMetadata = z.infer -const group = (entry: ZodTypeAny) => { - const groupEntry = entry.and(z.object({ "$meta": GroupMetadata })) - return z.optional(z.array(groupEntry).nonempty()); +const group = (obj: Record): ZodTypeAny => { + const meta = z.object({ "$meta": GroupMetadata.optional() }) + return z.object(obj).and(meta) +} + +const ModelHashes = z.object({ + a1111_shorthash: z.string().optional(), + sha256: z.string().optional(), +}).refine(({ a1111_shorthash, sha256 }) => + a1111_shorthash !== undefined || sha256 !== undefined, + { message: "At least one model hash must be specified" }) + +const GroupConditioning = group({ + text: z.string(), +}) +export type ComfyBoxStdGroupConditioning = z.infer + +const GroupCheckpoint = group({ + model_name: z.string().optional(), + model_hashes: ModelHashes.optional(), +}).refine(({ model_name, model_hashes }) => + model_name !== undefined || model_hashes !== undefined, + { message: "Must include either model name or model hash" } +) +export type ComfyBoxStdGroupCheckpoint = z.infer + +const GroupVAE = group({ + model_name: z.string().optional(), + model_hashes: ModelHashes.optional(), + type: z.enum(["internal", "external"]) +}).refine(({ model_name, model_hashes }) => + model_name !== undefined || model_hashes !== undefined, + { message: "Must include either model name or model hashes" } +) +export type ComfyBoxStdGroupVAE = z.infer + +const GroupKSampler = group({ + cfg_scale: z.number(), + seed: z.number(), + steps: z.number(), + sampler_name: z.string(), + scheduler: z.string(), + denoise: z.number().default(1.0), + type: z.enum(["empty", "image", "upscale"]).optional() +}) +export type ComfyBoxStdGroupKSampler = z.infer + +const GroupLatentImage = group({ + width: z.number(), + height: z.number(), + mask_blur: z.number().optional(), + batch_count: z.number().default(1).optional(), + batch_pos: z.number().default(0).optional() +}) +export type ComfyBoxStdGroupLatentImage = z.infer + +const GroupLatentUpscale = group({ + width: z.number(), + height: z.number(), + upscale_method: z.string().optional(), + upscale_by: z.number().optional(), + crop: z.string().optional() +}) +export type ComfyBoxStdGroupLatentUpscale = z.infer + +const GroupSDUpscale = group({ + upscaler: z.string(), + overlap: z.number(), +}) +export type ComfyBoxStdGroupSDUpscale = z.infer + +const GroupSelfAttentionGuidance = group({ + guidance_scale: z.number(), + mask_threshold: z.number(), +}) +export type ComfyBoxStdGroupSelfAttentionGuidance = z.infer + +const GroupHypernetwork = group({ + model_name: z.string(), + model_hashes: ModelHashes.optional(), + strength: z.number() +}) +export type ComfyBoxStdGroupHypernetwork = z.infer + +const LoRAModelHashes = z.object({ + addnet_shorthash: z.string().optional(), + addnet_shorthash_legacy: z.string().optional(), + sha256: z.string().optional(), +}).refine(({ addnet_shorthash, addnet_shorthash_legacy, sha256 }) => + addnet_shorthash !== undefined || addnet_shorthash_legacy !== undefined || sha256 !== undefined, + { message: "At least one model hash must be specified" }) + +const GroupLoRA = group({ + model_name: z.string(), + module_name: z.string().optional(), + model_hashes: LoRAModelHashes.optional(), + strength_unet: z.number(), + strength_tenc: z.number() +}) +export type ComfyBoxStdGroupLoRA = z.infer + +const GroupControlNet = group({ + model: z.string(), + model_hashes: ModelHashes.optional(), + strength: z.number(), +}) +export type ComfyBoxStdGroupControlNet = z.infer + +const GroupCLIP = group({ + clip_skip: z.number().optional() +}) +export type ComfyBoxStdGroupCLIP = z.infer + +const GroupDynamicThresholding = group({ + mimic_scale: z.number(), + threshold_percentile: z.number(), + mimic_mode: z.string(), + mimic_scale_minimum: z.number(), + cfg_mode: z.string(), + cfg_scale_minimum: z.number() +}) +export type ComfyBoxStdGroupDynamicThresholding = z.infer + +const GroupAestheticEmbedding = group({ + model_name: z.string(), + lr: z.number(), + slerp: z.boolean(), + slerp_angle: z.number().optional(), + steps: z.number(), + text: z.string(), + text_negative: z.boolean(), + weight: z.number(), +}) +export type ComfyBoxStdGroupAestheticEmbedding = z.infer + +const GroupDDetailer = group({ + 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(), + preprocess: z.boolean(), + inpaint_full: z.boolean(), + inpaint_padding: z.number(), + cfg: z.number() +}) +export type ComfyBoxStdGroupDDetailer = z.infer + +const groupArray = (entry: ZodTypeAny) => { + return z.optional(z.array(entry).nonempty()); } const Parameters = z.object({ - conditioning: group(GroupConditioning), - checkpoint: group(GroupCheckpoint), - vae: group(GroupVAE), - k_sampler: group(GroupKSampler), - clip: group(GroupCLIP), - latent_image: group(GroupLatentImage), - sd_upscale: group(GroupSDUpscale), - hypernetwork: group(GroupHypernetwork), - lora: group(GroupLoRA), - control_net: group(GroupControlNet), - dynamic_thresholding: group(GroupDynamicThresholding), - self_attention_guidance: group(GroupSelfAttentionGuidance), - ddetailer: group(GroupDDetailer) + conditioning: groupArray(GroupConditioning), + checkpoint: groupArray(GroupCheckpoint), + vae: groupArray(GroupVAE), + k_sampler: groupArray(GroupKSampler), + clip: groupArray(GroupCLIP), + latent_image: groupArray(GroupLatentImage), + latent_upscale: groupArray(GroupLatentUpscale), + sd_upscale: groupArray(GroupSDUpscale), + hypernetwork: groupArray(GroupHypernetwork), + lora: groupArray(GroupLoRA), + control_net: groupArray(GroupControlNet), + dynamic_thresholding: groupArray(GroupDynamicThresholding), + aesthetic_embedding: groupArray(GroupAestheticEmbedding), + self_attention_guidance: groupArray(GroupSelfAttentionGuidance), + ddetailer: groupArray(GroupDDetailer) }).partial() export type ComfyBoxStdParameters = z.infer diff --git a/src/lib/ComfyBoxStdPromptSerializer.ts b/src/lib/ComfyBoxStdPromptSerializer.ts new file mode 100644 index 0000000..86f9714 --- /dev/null +++ b/src/lib/ComfyBoxStdPromptSerializer.ts @@ -0,0 +1,55 @@ +import type { ComfyBoxStdGroupLoRA, ComfyBoxStdPrompt } from "$lib/ComfyBoxStdPrompt"; +import type { SerializedPrompt, SerializedPromptInputs } from "./components/ComfyApp"; + +export type ComfyPromptConverter = (stdPrompt: ComfyBoxStdPrompt, inputs: SerializedPromptInputs, nodeID: ComfyNodeID) => void; + +function LoraLoader(stdPrompt: ComfyBoxStdPrompt, inputs: SerializedPromptInputs) { + const params = stdPrompt.parameters + + const lora: ComfyBoxStdGroupLoRA = { + model_name: inputs["lora_name"], + strength_unet: inputs["strength_model"], + strength_tenc: inputs["strength_clip"] + } + + if (params.lora) + params.lora.push(lora) + else + params.lora = [lora] +} + +const ALL_CONVERTERS: Record = { + LoraLoader +} + +const COMMIT_HASH: string = __GIT_COMMIT_HASH__; + +export default class ComfyBoxStdPromptSerializer { + serialize(prompt: SerializedPrompt): ComfyBoxStdPrompt { + const stdPrompt: ComfyBoxStdPrompt = { + version: 1, + metadata: { + created_with: "ComfyBox", + commit_hash: COMMIT_HASH, + extra_data: { + comfybox: { + } + } + }, + parameters: {} + } + + for (const [nodeID, inputs] of Object.entries(prompt.output)) { + const classType = inputs.class_type + const converter = ALL_CONVERTERS[classType] + if (converter) { + converter(stdPrompt, inputs.inputs, nodeID) + } + else { + console.warn("No StdPrompt type converter for comfy class!", classType) + } + } + + return stdPrompt + } +} diff --git a/src/lib/comfyStdPromptConverters.ts b/src/lib/comfyStdPromptConverters.ts deleted file mode 100644 index 5148412..0000000 --- a/src/lib/comfyStdPromptConverters.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { ComfyBoxStdGroupLoRA, ComfyBoxStdPrompt } from "./ComfyBoxStdPrompt"; -import type { ComfyNodeID } from "./api"; -import type { SerializedPromptInputs } from "./components/ComfyApp"; -import type { ComfyBackendNode } from "./nodes/ComfyBackendNode"; - -export type ComfyPromptConverter = (stdPrompt: ComfyBoxStdPrompt, inputs: SerializedPromptInputs, nodeID: ComfyNodeID) => void; - -function LoraLoader(stdPrompt: ComfyBoxStdPrompt, inputs: SerializedPromptInputs) { - const params = stdPrompt.prompt.parameters - - const lora: ComfyBoxStdGroupLoRA = { - model_name: inputs["lora_name"], - strength_unet: inputs["strength_model"], - strength_tenc: inputs["strength_clip"] - } - - if (params.lora) - params.lora.push(lora) - else - params.lora = [lora] -} - -const converters: Record = { - LoraLoader -} -export default converters; diff --git a/src/lib/components/ComfyApp.ts b/src/lib/components/ComfyApp.ts index 941168b..d49fbe2 100644 --- a/src/lib/components/ComfyApp.ts +++ b/src/lib/components/ComfyApp.ts @@ -40,7 +40,7 @@ import { ComfyComboNode } from "$lib/nodes/widgets"; import parseA1111, { type A1111ParsedInfotext } from "$lib/parseA1111"; import convertA1111ToStdPrompt from "$lib/convertA1111ToStdPrompt"; import type { ComfyBoxStdPrompt } from "$lib/ComfyBoxStdPrompt"; -import ComfyBoxStdPromptSerializer from "./ComfyBoxStdPromptSerializer"; +import ComfyBoxStdPromptSerializer from "$lib/ComfyBoxStdPromptSerializer"; export const COMFYBOX_SERIAL_VERSION = 1; diff --git a/src/lib/components/ComfyBoxStdPromptSerializer.ts b/src/lib/components/ComfyBoxStdPromptSerializer.ts deleted file mode 100644 index b1d145f..0000000 --- a/src/lib/components/ComfyBoxStdPromptSerializer.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { ComfyBoxStdPrompt } from "$lib/ComfyBoxStdPrompt"; -import type { SerializedPrompt } from "./ComfyApp"; -import comfyStdPromptConverters from "$lib/comfyStdPromptConverters" - -const COMMIT_HASH: string = "asdf"; - -export default class ComfyBoxStdPromptSerializer { - serialize(prompt: SerializedPrompt): ComfyBoxStdPrompt { - const stdPrompt: ComfyBoxStdPrompt = { - version: 1, - metadata: { - created_with: "ComfyBox", - commit_hash: COMMIT_HASH, - extra_data: { - comfybox: { - } - } - }, - parameters: {} - } - - for (const [nodeID, inputs] of Object.entries(prompt.output)) { - const classType = inputs.class_type - const converter = comfyStdPromptConverters[classType] - if (converter) { - converter(stdPrompt, inputs.inputs, nodeID) - } - else { - console.warn("No StdPrompt type converter for comfy class!", classType) - } - } - - return stdPrompt - } -} diff --git a/src/lib/convertA1111ToStdPrompt.ts b/src/lib/convertA1111ToStdPrompt.ts index 5bebdc1..5fbdd85 100644 --- a/src/lib/convertA1111ToStdPrompt.ts +++ b/src/lib/convertA1111ToStdPrompt.ts @@ -1,4 +1,4 @@ -import type { ComfyBoxStdGroupCheckpoint, ComfyBoxStdGroupDDetailer, ComfyBoxStdGroupDynamicThresholding, ComfyBoxStdGroupHypernetwork, ComfyBoxStdGroupKSampler, ComfyBoxStdGroupLatentImage, ComfyBoxStdGroupLoRA, ComfyBoxStdGroupSelfAttentionGuidance, ComfyBoxStdParameters, ComfyBoxStdPrompt } from "./ComfyBoxStdPrompt"; +import type { ComfyBoxStdGroupAestheticEmbedding, ComfyBoxStdGroupCheckpoint, ComfyBoxStdGroupDDetailer, ComfyBoxStdGroupDynamicThresholding, ComfyBoxStdGroupHypernetwork, ComfyBoxStdGroupKSampler, ComfyBoxStdGroupLatentImage, ComfyBoxStdGroupLatentUpscale, ComfyBoxStdGroupLoRA, ComfyBoxStdGroupSelfAttentionGuidance, ComfyBoxStdParameters, ComfyBoxStdPrompt } from "./ComfyBoxStdPrompt"; import type { A1111ParsedInfotext } from "./parseA1111"; function getSamplerAndScheduler(a1111Sampler: string): [string, string] { @@ -13,14 +13,14 @@ function getSamplerAndScheduler(a1111Sampler: string): [string, string] { return [name, scheduler] } -const reAddNetModelName = /^([^(]+)\(([^)]+)\)$/; +const reAddNetModelName = /^([^(]+)\((.+)\)$/; function parseAddNetModelNameAndHash(name: string | null): [string | undefined, string | undefined] { if (!name) return [undefined, undefined] const match = name.match(reAddNetModelName); - if (match) { + if (match != null) { return [match[1], match[2]] } return [undefined, undefined] @@ -34,7 +34,7 @@ function parseDDetailerModelNameAndHash(name: string | null): [string | undefine // bbox\mmdet_anime-face_yolov3.pth [51e1af4a] const match = name.match(reDDetailerModelName); - if (match) { + if (match != null) { return [match[1], match[2]] } return [undefined, undefined] @@ -51,13 +51,13 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): parameters.conditioning = [ { - "^meta": { + "$meta": { types: ["positive"] }, text: infotext.positive, }, { - "^meta": { + "$meta": { types: ["negative"] }, text: infotext.negative, @@ -100,16 +100,13 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): uw = +hrWidth; uh = +hrHeight; } - const hr_image: ComfyBoxStdGroupLatentImage = { - type: "upscale", + const hr: ComfyBoxStdGroupLatentUpscale = { width: uw, height: uh, upscale_by: hrScaleBy, - batch_count: infotext.batchSize, - batch_pos: infotext.batchPos, upscale_method: hrMethod } - parameters.latent_image.push(hr_image) + parameters.latent_upscale = [hr]; } const [sampler_name, scheduler] = getSamplerAndScheduler(infotext.sampler) @@ -126,7 +123,9 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): if (hrMethod != null) { const k_sampler_hr: ComfyBoxStdGroupKSampler = { - type: "upscale", + "$meta": { + types: ["upscale"] + }, steps: hrSteps != null ? parseInt(hrSteps) : infotext.steps, seed: infotext.seed, cfg_scale: infotext.cfgScale, @@ -163,6 +162,21 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): }] } + if ("aesthetic embedding" in infotext.extraParams) { + const slerp = popOpt("aesthetic slerp") === "True" + const aesthetic_embedding: ComfyBoxStdGroupAestheticEmbedding = { + model_name: popOpt("aesthetic embedding"), + lr: parseFloat(popOpt("aesthetic lr")), + slerp, + slerp_angle: parseFloat(popOpt("aesthetic slerp angle")), + steps: parseInt(popOpt("aesthetic steps")), + text: popOpt("aesthetic text"), + text_negative: popOpt("aesthetic text negative") === "True", + weight: parseFloat(popOpt("aesthetic weight")), + } + parameters.aesthetic_embedding = [aesthetic_embedding] + } + if ("dynamic thresholding enabled" in infotext.extraParams) { const dtEnabled = popOpt("dynamic thresholding enabled") if (dtEnabled === "True") { @@ -287,8 +301,15 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): popOpt("addnet enabled") const moduleName = popOpt(`addnet module ${index}`) const modelName = popOpt(`addnet model ${index}`); - const weightA = popOpt(`addnet weight a ${index}`); - const weightB = popOpt(`addnet weight b ${index}`); + const weight = popOpt(`addnet weight ${index}`); + let weightA = popOpt(`addnet weight a ${index}`); + let weightB = popOpt(`addnet weight b ${index}`); + + if (weightA == null || weightB == null) { + // linked weights before addnet version update + weightA = weight; + weightB = weight; + } if (moduleName == null || modelName == null || weightA == null || weightB == null) { throw new Error(`Error parsing addnet model params: ${moduleName} ${modelName} ${weightA} ${weightB}`) @@ -300,7 +321,7 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): const [name, hash] = parseAddNetModelNameAndHash(modelName); if (name == null || hash == null) { - throw new Error("Error parsing addnet model name: " + modelName); + throw new Error("Error parsing addnet model name: " + JSON.stringify(modelName)); } let shorthash = undefined @@ -335,16 +356,17 @@ export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): let app_version = popOpt("version") + const extra_data: Record = {}; + if (Object.keys(infotext.extraParams).length > 0) { + extra_data.a1111 = { params: infotext.extraParams } + } + const prompt: ComfyBoxStdPrompt = { version: 1, metadata: { created_with: "stable-diffusion-webui", app_version, - extra_data: { - a1111: { - params: infotext.extraParams - } - } + extra_data }, parameters } diff --git a/src/tests/convertA1111ToStdPromptTests.ts b/src/tests/convertA1111ToStdPromptTests.ts index b20dee6..3774225 100644 --- a/src/tests/convertA1111ToStdPromptTests.ts +++ b/src/tests/convertA1111ToStdPromptTests.ts @@ -45,13 +45,13 @@ export default class convertA1111ToStdPromptTests extends UnitTest { } }], conditioning: [{ - "^meta": { + "$meta": { types: ["positive"] }, text: "highest quality, masterpiece, best quality, masterpiece, asuka langley sitting cross legged on a chair", }, { - "^meta": { - types: ["positive"] + "$meta": { + types: ["negative"] }, text: "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts,signature, watermark, username, blurry, artist name" }], @@ -69,11 +69,21 @@ export default class convertA1111ToStdPromptTests extends UnitTest { latent_image: [{ width: 512, height: 512, + }], + aesthetic_embedding: [{ + lr: 0.0005, + model_name: "Belle", + text: "", + text_negative: false, + slerp: false, + slerp_angle: 0.1, + steps: 15, + weight: 0.9 }] } }) - expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true); + expect(() => ComfyBoxStdPrompt.parse(converted)).not.toThrow(); } test__convertsExtraNetworks() { @@ -112,7 +122,13 @@ export default class convertA1111ToStdPromptTests extends UnitTest { version: 1, metadata: { created_with: "stable-diffusion-webui", - extra_data: {} + extra_data: { + a1111: { + params: { + "ensd": "31337" + } + } + } }, parameters: { checkpoint: [{ @@ -122,12 +138,12 @@ export default class convertA1111ToStdPromptTests extends UnitTest { } }], conditioning: [{ - "^meta": { + "$meta": { types: ["positive"] }, text: "dreamlike fantasy landscape where everything is a shade of pink,\n dog ", }, { - "^meta": { + "$meta": { types: ["negative"] }, text: "(worst quality:1.4), (low quality:1.4) , (monochrome:1.1)" @@ -141,6 +157,7 @@ export default class convertA1111ToStdPromptTests extends UnitTest { }], lora: [{ model_name: "asdfg", + module_name: "lora", strength_unet: 0.8, strength_tenc: 0.8, }], @@ -152,7 +169,9 @@ export default class convertA1111ToStdPromptTests extends UnitTest { seed: 2416682767, steps: 40 }, { - type: "upscale", + "$meta": { + types: ["upscale"] + }, cfg_scale: 12, denoise: 0.55, sampler_name: "dpmpp_2m", @@ -163,8 +182,8 @@ export default class convertA1111ToStdPromptTests extends UnitTest { latent_image: [{ width: 640, height: 512, - }, { - type: "upscale", + }], + latent_upscale: [{ width: 1280, height: 1024, upscale_by: 2, @@ -173,7 +192,7 @@ export default class convertA1111ToStdPromptTests extends UnitTest { } }) - expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true); + expect(() => ComfyBoxStdPrompt.parse(converted)).not.toThrow(); } test__convertsAdditionalNetworks() { @@ -217,7 +236,16 @@ export default class convertA1111ToStdPromptTests extends UnitTest { version: 1, metadata: { created_with: "stable-diffusion-webui", - extra_data: {} + extra_data: { + a1111: { + params: { + "ensd": "31337", + // TODO + "template": "1girl", + "negative template": "(worst quality", + } + } + } }, parameters: { checkpoint: [{ @@ -227,12 +255,12 @@ export default class convertA1111ToStdPromptTests extends UnitTest { } }], conditioning: [{ - "^meta": { + "$meta": { types: ["positive"] }, text: "1girl, pink hair", }, { - "^meta": { + "$meta": { types: ["negative"] }, text: "(worst quality, low quality:1.4)", @@ -275,6 +303,6 @@ export default class convertA1111ToStdPromptTests extends UnitTest { } }) - expect(ComfyBoxStdPrompt.safeParse(converted).success).toEqual(true); + expect(() => ComfyBoxStdPrompt.parse(converted)).not.toThrow(); } } diff --git a/vite.config.ts b/vite.config.ts index 9e6586f..8ace9de 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,6 +11,9 @@ const isProduction = process.env.NODE_ENV === "production"; console.log("Production build: " + isProduction) export default defineConfig({ + define: { + "__GIT_COMMIT_HASH__": '"asdf"' + }, clearScreen: false, base: "./", plugins: [