mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-06-12 01:09:36 +00:00
Compare commits
1 Commits
coderabbit
...
alexis/upd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c66843f6e |
@@ -1,373 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { externalLinks, getRoutes } from '../../config/routes'
|
||||
import { hasKey, t } from '../../i18n/translations'
|
||||
import {
|
||||
AFFILIATE_FAQ_COUNT,
|
||||
AFFILIATE_FAQ_HEADING_KEY,
|
||||
AFFILIATE_FAQ_PREFIX
|
||||
} from './affiliateFaqs'
|
||||
import { brandAssets } from './brandAssets'
|
||||
import { programDetailRows } from './programDetails'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// brandAssets.ts
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('brandAssets data integrity', () => {
|
||||
it('exports a non-empty array', () => {
|
||||
expect(Array.isArray(brandAssets)).toBe(true)
|
||||
expect(brandAssets.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('has exactly 8 brand assets', () => {
|
||||
expect(brandAssets).toHaveLength(8)
|
||||
})
|
||||
|
||||
it('every asset has a non-empty id', () => {
|
||||
for (const asset of brandAssets) {
|
||||
expect(asset.id.trim().length, `asset id is empty`).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset id is unique', () => {
|
||||
const ids = brandAssets.map((a) => a.id)
|
||||
const unique = new Set(ids)
|
||||
expect(unique.size).toBe(ids.length)
|
||||
})
|
||||
|
||||
it('every asset id uses kebab-case only (no spaces or uppercase letters)', () => {
|
||||
const kebabCase = /^[a-z0-9]+(-[a-z0-9]+)*$/
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
kebabCase.test(asset.id),
|
||||
`asset id "${asset.id}" is not kebab-case`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset download path is a non-empty string beginning with "/"', () => {
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
asset.download.length,
|
||||
`download path for "${asset.id}" is empty`
|
||||
).toBeGreaterThan(0)
|
||||
expect(
|
||||
asset.download.startsWith('/'),
|
||||
`download path for "${asset.id}" does not start with "/"`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset preview path is a non-empty string beginning with "/"', () => {
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
asset.preview.length,
|
||||
`preview path for "${asset.id}" is empty`
|
||||
).toBeGreaterThan(0)
|
||||
expect(
|
||||
asset.preview.startsWith('/'),
|
||||
`preview path for "${asset.id}" does not start with "/"`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset download path has a recognisable file extension', () => {
|
||||
const knownExtensions = /\.(svg|png|jpg|jpeg|webp|gif|zip)$/i
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
knownExtensions.test(asset.download),
|
||||
`download path "${asset.download}" has no recognised extension`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset titleKey is a valid translation key with non-empty English copy', () => {
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
hasKey(asset.titleKey),
|
||||
`titleKey "${asset.titleKey}" not found in translations`
|
||||
).toBe(true)
|
||||
expect(
|
||||
t(asset.titleKey, 'en').trim().length,
|
||||
`titleKey "${asset.titleKey}" has empty English copy`
|
||||
).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset titleKey starts with "affiliate-landing.assets.tile."', () => {
|
||||
const TILE_PREFIX = 'affiliate-landing.assets.tile.'
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
asset.titleKey.startsWith(TILE_PREFIX),
|
||||
`titleKey "${asset.titleKey}" does not start with "${TILE_PREFIX}"`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('the comfy-amplified-logo.png asset was removed (renamed to svg variants)', () => {
|
||||
// Regression guard: the PR deleted comfy-amplified-logo.png and the old PNG
|
||||
// download path should no longer appear in brandAssets.
|
||||
const hasPngAmplifiedLogo = brandAssets.some(
|
||||
(a) => a.download.endsWith('comfy-amplified-logo.png')
|
||||
)
|
||||
expect(hasPngAmplifiedLogo).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// programDetails.ts
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('programDetailRows data integrity', () => {
|
||||
it('exports a non-empty array', () => {
|
||||
expect(Array.isArray(programDetailRows)).toBe(true)
|
||||
expect(programDetailRows.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('has exactly 6 program detail rows', () => {
|
||||
expect(programDetailRows).toHaveLength(6)
|
||||
})
|
||||
|
||||
it('all labelKeys are unique', () => {
|
||||
const labelKeys = programDetailRows.map((r) => r.labelKey)
|
||||
const unique = new Set(labelKeys)
|
||||
expect(unique.size).toBe(labelKeys.length)
|
||||
})
|
||||
|
||||
it('all valueKeys are unique', () => {
|
||||
const valueKeys = programDetailRows.map((r) => r.valueKey)
|
||||
const unique = new Set(valueKeys)
|
||||
expect(unique.size).toBe(valueKeys.length)
|
||||
})
|
||||
|
||||
it('no row shares a labelKey with its valueKey', () => {
|
||||
for (const row of programDetailRows) {
|
||||
expect(row.labelKey).not.toBe(row.valueKey)
|
||||
}
|
||||
})
|
||||
|
||||
it('all labelKeys are valid translation keys with non-empty English copy', () => {
|
||||
for (const row of programDetailRows) {
|
||||
expect(
|
||||
hasKey(row.labelKey),
|
||||
`labelKey "${row.labelKey}" not found in translations`
|
||||
).toBe(true)
|
||||
expect(
|
||||
t(row.labelKey, 'en').trim().length,
|
||||
`labelKey "${row.labelKey}" has empty English copy`
|
||||
).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('all valueKeys are valid translation keys with non-empty English copy', () => {
|
||||
for (const row of programDetailRows) {
|
||||
expect(
|
||||
hasKey(row.valueKey),
|
||||
`valueKey "${row.valueKey}" not found in translations`
|
||||
).toBe(true)
|
||||
expect(
|
||||
t(row.valueKey, 'en').trim().length,
|
||||
`valueKey "${row.valueKey}" has empty English copy`
|
||||
).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('all labelKeys follow the "affiliate-landing.details.row.<n>.label" pattern', () => {
|
||||
const pattern = /^affiliate-landing\.details\.row\.\d+\.label$/
|
||||
for (const row of programDetailRows) {
|
||||
expect(
|
||||
pattern.test(row.labelKey),
|
||||
`labelKey "${row.labelKey}" does not match expected pattern`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('all valueKeys follow the "affiliate-landing.details.row.<n>.value" pattern', () => {
|
||||
const pattern = /^affiliate-landing\.details\.row\.\d+\.value$/
|
||||
for (const row of programDetailRows) {
|
||||
expect(
|
||||
pattern.test(row.valueKey),
|
||||
`valueKey "${row.valueKey}" does not match expected pattern`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('row indices are zero-based and contiguous', () => {
|
||||
const indexRegex = /\.row\.(\d+)\.label$/
|
||||
const indices = programDetailRows
|
||||
.map((r) => r.labelKey.match(indexRegex)?.[1])
|
||||
.filter((m): m is string => m !== undefined)
|
||||
.map((s) => parseInt(s, 10))
|
||||
expect(indices).toEqual(
|
||||
Array.from({ length: programDetailRows.length }, (_, i) => i)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// affiliateFaqs.ts — constant values and types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('affiliateFaqs constants', () => {
|
||||
it('AFFILIATE_FAQ_PREFIX is exactly "affiliate-landing.faq"', () => {
|
||||
expect(AFFILIATE_FAQ_PREFIX).toBe('affiliate-landing.faq')
|
||||
})
|
||||
|
||||
it('AFFILIATE_FAQ_HEADING_KEY is exactly "affiliate-landing.faq.heading"', () => {
|
||||
expect(AFFILIATE_FAQ_HEADING_KEY).toBe('affiliate-landing.faq.heading')
|
||||
})
|
||||
|
||||
it('AFFILIATE_FAQ_HEADING_KEY starts with AFFILIATE_FAQ_PREFIX', () => {
|
||||
expect(AFFILIATE_FAQ_HEADING_KEY.startsWith(AFFILIATE_FAQ_PREFIX)).toBe(
|
||||
true
|
||||
)
|
||||
})
|
||||
|
||||
it('AFFILIATE_FAQ_COUNT is a positive integer', () => {
|
||||
expect(Number.isInteger(AFFILIATE_FAQ_COUNT)).toBe(true)
|
||||
expect(AFFILIATE_FAQ_COUNT).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('AFFILIATE_FAQ_COUNT is 8 (regression guard against accidental changes)', () => {
|
||||
expect(AFFILIATE_FAQ_COUNT).toBe(8)
|
||||
})
|
||||
|
||||
it('AFFILIATE_FAQ_HEADING_KEY resolves to a non-empty English string', () => {
|
||||
expect(hasKey(AFFILIATE_FAQ_HEADING_KEY)).toBe(true)
|
||||
expect(t(AFFILIATE_FAQ_HEADING_KEY, 'en').trim().length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('there are no FAQ keys beyond AFFILIATE_FAQ_COUNT', () => {
|
||||
const beyondCount = hasKey(
|
||||
`${AFFILIATE_FAQ_PREFIX}.${AFFILIATE_FAQ_COUNT + 1}.q` as never
|
||||
)
|
||||
expect(beyondCount).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FooterCtaSection.vue config dependencies
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('FooterCtaSection config dependencies', () => {
|
||||
it('externalLinks.affiliateApplicationForm is the canonical Google Form URL', () => {
|
||||
expect(externalLinks.affiliateApplicationForm).toBe(
|
||||
'https://forms.gle/RS8L2ttcuGap4Q1v6'
|
||||
)
|
||||
})
|
||||
|
||||
it('externalLinks.affiliateApplicationForm is a well-formed https URL', () => {
|
||||
expect(() => new URL(externalLinks.affiliateApplicationForm)).not.toThrow()
|
||||
expect(
|
||||
new URL(externalLinks.affiliateApplicationForm).protocol
|
||||
).toBe('https:')
|
||||
})
|
||||
|
||||
it('affiliateTerms route is "/affiliates/terms" for English locale', () => {
|
||||
expect(getRoutes('en').affiliateTerms).toBe('/affiliates/terms')
|
||||
})
|
||||
|
||||
it('affiliateTerms route is locale-invariant (same for zh-CN)', () => {
|
||||
// Guards against re-introducing /zh-CN/affiliates/terms, which would
|
||||
// bypass the legal review that applies only to the English copy.
|
||||
expect(getRoutes('zh-CN').affiliateTerms).toBe('/affiliates/terms')
|
||||
})
|
||||
|
||||
it('affiliates base route uses the expected path', () => {
|
||||
expect(getRoutes('en').affiliates).toBe('/affiliates')
|
||||
})
|
||||
|
||||
it('footer CTA copy keys are present in translations', () => {
|
||||
expect(hasKey('affiliate-landing.footerCta.heading')).toBe(true)
|
||||
expect(hasKey('affiliate-landing.footerCta.termsLink')).toBe(true)
|
||||
expect(hasKey('affiliate-landing.cta.apply')).toBe(true)
|
||||
expect(hasKey('affiliate-landing.cta.applyAriaLabel')).toBe(true)
|
||||
})
|
||||
|
||||
it('footer CTA copy keys return non-empty English strings', () => {
|
||||
const keys = [
|
||||
'affiliate-landing.footerCta.heading',
|
||||
'affiliate-landing.footerCta.termsLink',
|
||||
'affiliate-landing.cta.apply',
|
||||
'affiliate-landing.cta.applyAriaLabel'
|
||||
] as const
|
||||
for (const key of keys) {
|
||||
expect(t(key, 'en').trim().length, `key "${key}" is empty`).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AudienceSection.vue — translation key contract
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('AudienceSection translation keys', () => {
|
||||
const AUDIENCE_ITEM_COUNT = 5
|
||||
const AUDIENCE_PREFIX = 'affiliate-landing.audience'
|
||||
|
||||
it('audience heading key exists and is non-empty', () => {
|
||||
expect(hasKey(`${AUDIENCE_PREFIX}.heading`)).toBe(true)
|
||||
expect(t(`${AUDIENCE_PREFIX}.heading` as never, 'en').trim().length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it(`provides exactly ${AUDIENCE_ITEM_COUNT} audience item keys (item.0 through item.4)`, () => {
|
||||
for (let i = 0; i < AUDIENCE_ITEM_COUNT; i++) {
|
||||
expect(
|
||||
hasKey(`${AUDIENCE_PREFIX}.item.${i}`),
|
||||
`missing key: ${AUDIENCE_PREFIX}.item.${i}`
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('does not have an audience item beyond index 4 (prevents silent skipping)', () => {
|
||||
expect(hasKey(`${AUDIENCE_PREFIX}.item.${AUDIENCE_ITEM_COUNT}` as never)).toBe(false)
|
||||
})
|
||||
|
||||
it('all audience item keys return non-empty English text', () => {
|
||||
for (let i = 0; i < AUDIENCE_ITEM_COUNT; i++) {
|
||||
const key = `${AUDIENCE_PREFIX}.item.${i}` as never
|
||||
expect(
|
||||
t(key, 'en').trim().length,
|
||||
`audience item ${i} has empty English copy`
|
||||
).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// BrandAssetsSection.vue — section-level translation key contract
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('BrandAssetsSection translation keys', () => {
|
||||
const ASSETS_PREFIX = 'affiliate-landing.assets'
|
||||
|
||||
it('heading, subheading, and downloadLabel keys all exist', () => {
|
||||
expect(hasKey(`${ASSETS_PREFIX}.heading`)).toBe(true)
|
||||
expect(hasKey(`${ASSETS_PREFIX}.subheading`)).toBe(true)
|
||||
expect(hasKey(`${ASSETS_PREFIX}.downloadLabel`)).toBe(true)
|
||||
})
|
||||
|
||||
it('all section-level keys return non-empty English copy', () => {
|
||||
const keys = [
|
||||
`${ASSETS_PREFIX}.heading`,
|
||||
`${ASSETS_PREFIX}.subheading`,
|
||||
`${ASSETS_PREFIX}.downloadLabel`
|
||||
] as const
|
||||
for (const key of keys) {
|
||||
expect(t(key as never, 'en').trim().length, `key "${key}" is empty`).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it('every asset titleKey starts under the tile namespace', () => {
|
||||
const tilePrefix = `${ASSETS_PREFIX}.tile.`
|
||||
for (const asset of brandAssets) {
|
||||
expect(
|
||||
asset.titleKey.startsWith(tilePrefix),
|
||||
`titleKey "${asset.titleKey}" doesn't start with "${tilePrefix}"`
|
||||
).toBe(true)
|
||||
}
|
||||
// Guard: the BrandAssetsSection renders one card per entry in brandAssets
|
||||
expect(brandAssets.length).toBe(8)
|
||||
})
|
||||
})
|
||||
@@ -1,150 +1,414 @@
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
|
||||
export const defaultGraph: ComfyWorkflowJSON = {
|
||||
last_node_id: 9,
|
||||
last_link_id: 9,
|
||||
last_node_id: 71,
|
||||
last_link_id: 82,
|
||||
nodes: [
|
||||
{
|
||||
id: 7,
|
||||
type: 'CLIPTextEncode',
|
||||
pos: [413, 389],
|
||||
size: [425.27801513671875, 180.6060791015625],
|
||||
id: 9,
|
||||
type: 'SaveImage',
|
||||
pos: [1279.9999726783708, 319.9999392082668],
|
||||
size: [300, 420],
|
||||
flags: {},
|
||||
order: 3,
|
||||
order: 9,
|
||||
mode: 0,
|
||||
inputs: [{ name: 'clip', type: 'CLIP', link: 5 }],
|
||||
outputs: [
|
||||
inputs: [
|
||||
{
|
||||
name: 'CONDITIONING',
|
||||
type: 'CONDITIONING',
|
||||
links: [6],
|
||||
slot_index: 0
|
||||
name: 'images',
|
||||
type: 'IMAGE',
|
||||
link: 80
|
||||
}
|
||||
],
|
||||
properties: {},
|
||||
widgets_values: ['text, watermark']
|
||||
outputs: [],
|
||||
properties: {
|
||||
'Node name for S&R': 'SaveImage',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.64',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: ['ComfyUI']
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
type: 'CLIPTextEncode',
|
||||
pos: [415, 186],
|
||||
size: [422.84503173828125, 164.31304931640625],
|
||||
id: 62,
|
||||
type: 'CLIPLoader',
|
||||
pos: [-239.9999987113997, 420.0000536491848],
|
||||
size: [340, 169.3125],
|
||||
flags: {},
|
||||
order: 2,
|
||||
order: 0,
|
||||
mode: 0,
|
||||
inputs: [{ name: 'clip', type: 'CLIP', link: 3 }],
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'CONDITIONING',
|
||||
type: 'CONDITIONING',
|
||||
links: [4],
|
||||
slot_index: 0
|
||||
name: 'CLIP',
|
||||
type: 'CLIP',
|
||||
links: [79, 81]
|
||||
}
|
||||
],
|
||||
properties: {},
|
||||
widgets_values: [
|
||||
'beautiful scenery nature glass bottle landscape, , purple galaxy bottle,'
|
||||
]
|
||||
properties: {
|
||||
'Node name for S&R': 'CLIPLoader',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.73',
|
||||
models: [
|
||||
{
|
||||
name: 'qwen_3_4b.safetensors',
|
||||
url: 'https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/text_encoders/qwen_3_4b.safetensors',
|
||||
directory: 'text_encoders'
|
||||
}
|
||||
],
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: ['qwen_3_4b.safetensors', 'lumina2', 'default']
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'EmptyLatentImage',
|
||||
pos: [473, 609],
|
||||
size: [315, 106],
|
||||
id: 63,
|
||||
type: 'VAELoader',
|
||||
pos: [659.9998200904802, 699.9998629143215],
|
||||
size: [320, 106.65625],
|
||||
flags: {},
|
||||
order: 1,
|
||||
mode: 0,
|
||||
outputs: [{ name: 'LATENT', type: 'LATENT', links: [2], slot_index: 0 }],
|
||||
properties: {},
|
||||
widgets_values: [512, 512, 1]
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'VAE',
|
||||
type: 'VAE',
|
||||
links: [74]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'VAELoader',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.73',
|
||||
models: [
|
||||
{
|
||||
name: 'ae.safetensors',
|
||||
url: 'https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/vae/ae.safetensors',
|
||||
directory: 'vae'
|
||||
}
|
||||
],
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: ['ae.safetensors']
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'KSampler',
|
||||
pos: [863, 186],
|
||||
size: [315, 262],
|
||||
id: 65,
|
||||
type: 'VAEDecode',
|
||||
pos: [1019.9998200904802, 319.9999392082668],
|
||||
size: [225, 96],
|
||||
flags: {},
|
||||
order: 8,
|
||||
mode: 0,
|
||||
inputs: [
|
||||
{
|
||||
name: 'samples',
|
||||
type: 'LATENT',
|
||||
link: 73
|
||||
},
|
||||
{
|
||||
name: 'vae',
|
||||
type: 'VAE',
|
||||
link: 74
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'IMAGE',
|
||||
type: 'IMAGE',
|
||||
slot_index: 0,
|
||||
links: [80]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'VAEDecode',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.64',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: []
|
||||
},
|
||||
{
|
||||
id: 66,
|
||||
type: 'UNETLoader',
|
||||
pos: [-239.9999987113997, 110.00000596546897],
|
||||
size: [380, 134.65625],
|
||||
flags: {},
|
||||
order: 2,
|
||||
mode: 0,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'MODEL',
|
||||
type: 'MODEL',
|
||||
links: [72]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'UNETLoader',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.73',
|
||||
models: [
|
||||
{
|
||||
name: 'z_image_turbo_bf16.safetensors',
|
||||
url: 'https://huggingface.co/Comfy-Org/z_image_turbo/resolve/main/split_files/diffusion_models/z_image_turbo_bf16.safetensors',
|
||||
directory: 'diffusion_models'
|
||||
}
|
||||
],
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: ['z_image_turbo_bf16.safetensors', 'default']
|
||||
},
|
||||
{
|
||||
id: 67,
|
||||
type: 'CLIPTextEncode',
|
||||
pos: [170.00001082534345, 290.0000536491848],
|
||||
size: [410, 160],
|
||||
flags: {},
|
||||
order: 4,
|
||||
mode: 0,
|
||||
inputs: [
|
||||
{ name: 'model', type: 'MODEL', link: 1 },
|
||||
{ name: 'positive', type: 'CONDITIONING', link: 4 },
|
||||
{ name: 'negative', type: 'CONDITIONING', link: 6 },
|
||||
{ name: 'latent_image', type: 'LATENT', link: 2 }
|
||||
{
|
||||
name: 'clip',
|
||||
type: 'CLIP',
|
||||
link: 79
|
||||
}
|
||||
],
|
||||
outputs: [{ name: 'LATENT', type: 'LATENT', links: [7], slot_index: 0 }],
|
||||
properties: {},
|
||||
widgets_values: [156680208700286, true, 20, 8, 'euler', 'normal', 1]
|
||||
outputs: [
|
||||
{
|
||||
name: 'CONDITIONING',
|
||||
type: 'CONDITIONING',
|
||||
links: [76]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'CLIPTextEncode',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.73',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: [
|
||||
'anime RPG game style, cute anime girl with gigantic fennec ears and a big fluffy fox tail with long wavy blonde hair and large blue eyes blonde colored eyelashes wearing a pink sweater a large oversized gold trimmed black winter coat and a long blue maxi skirt and a red scarf, she is sitting beside a campfire in the wilderness at night playing guitar with a milky way galaxy sky'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
type: 'VAEDecode',
|
||||
pos: [1209, 188],
|
||||
size: [210, 46],
|
||||
id: 68,
|
||||
type: 'EmptySD3LatentImage',
|
||||
pos: [310.0000489723161, 700.0000155022121],
|
||||
size: [260, 168],
|
||||
flags: {},
|
||||
order: 3,
|
||||
mode: 0,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
name: 'LATENT',
|
||||
type: 'LATENT',
|
||||
slot_index: 0,
|
||||
links: [78]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'EmptySD3LatentImage',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.64',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: [1024, 1024, 1]
|
||||
},
|
||||
{
|
||||
id: 69,
|
||||
type: 'ModelSamplingAuraFlow',
|
||||
pos: [220.00001082534345, 110.00000596546897],
|
||||
size: [310, 104],
|
||||
flags: {},
|
||||
order: 6,
|
||||
mode: 0,
|
||||
inputs: [
|
||||
{
|
||||
name: 'model',
|
||||
type: 'MODEL',
|
||||
link: 72
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'MODEL',
|
||||
type: 'MODEL',
|
||||
slot_index: 0,
|
||||
links: [75]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'ModelSamplingAuraFlow',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.64',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: [3]
|
||||
},
|
||||
{
|
||||
id: 70,
|
||||
type: 'KSampler',
|
||||
pos: [659.9998200904802, 319.9999392082668],
|
||||
size: [315, 341.3125],
|
||||
flags: {},
|
||||
order: 7,
|
||||
mode: 0,
|
||||
inputs: [
|
||||
{
|
||||
name: 'model',
|
||||
type: 'MODEL',
|
||||
link: 75
|
||||
},
|
||||
{
|
||||
name: 'positive',
|
||||
type: 'CONDITIONING',
|
||||
link: 76
|
||||
},
|
||||
{
|
||||
name: 'negative',
|
||||
type: 'CONDITIONING',
|
||||
link: 82
|
||||
},
|
||||
{
|
||||
name: 'latent_image',
|
||||
type: 'LATENT',
|
||||
link: 78
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
name: 'LATENT',
|
||||
type: 'LATENT',
|
||||
slot_index: 0,
|
||||
links: [73]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
'Node name for S&R': 'KSampler',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.64',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: [42, 'fixed', 8, 1, 'res_multistep', 'simple', 1]
|
||||
},
|
||||
{
|
||||
id: 71,
|
||||
type: 'CLIPTextEncode',
|
||||
pos: [170.00001082534345, 520.0000536491848],
|
||||
size: [405.46875, 140],
|
||||
flags: {},
|
||||
order: 5,
|
||||
mode: 0,
|
||||
inputs: [
|
||||
{ name: 'samples', type: 'LATENT', link: 7 },
|
||||
{ name: 'vae', type: 'VAE', link: 8 }
|
||||
{
|
||||
name: 'clip',
|
||||
type: 'CLIP',
|
||||
link: 81
|
||||
}
|
||||
],
|
||||
outputs: [{ name: 'IMAGE', type: 'IMAGE', links: [9], slot_index: 0 }],
|
||||
properties: {}
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
type: 'SaveImage',
|
||||
pos: [1451, 189],
|
||||
size: [210, 26],
|
||||
flags: {},
|
||||
order: 6,
|
||||
mode: 0,
|
||||
inputs: [{ name: 'images', type: 'IMAGE', link: 9 }],
|
||||
properties: {}
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'CheckpointLoaderSimple',
|
||||
pos: [26, 474],
|
||||
size: [315, 98],
|
||||
flags: {},
|
||||
order: 0,
|
||||
mode: 0,
|
||||
outputs: [
|
||||
{ name: 'MODEL', type: 'MODEL', links: [1], slot_index: 0 },
|
||||
{ name: 'CLIP', type: 'CLIP', links: [3, 5], slot_index: 1 },
|
||||
{ name: 'VAE', type: 'VAE', links: [8], slot_index: 2 }
|
||||
{
|
||||
name: 'CONDITIONING',
|
||||
type: 'CONDITIONING',
|
||||
links: [82]
|
||||
}
|
||||
],
|
||||
properties: {
|
||||
models: [
|
||||
{
|
||||
name: 'v1-5-pruned-emaonly-fp16.safetensors',
|
||||
url: 'https://huggingface.co/Comfy-Org/stable-diffusion-v1-5-archive/resolve/main/v1-5-pruned-emaonly-fp16.safetensors',
|
||||
directory: 'checkpoints'
|
||||
}
|
||||
]
|
||||
'Node name for S&R': 'CLIPTextEncode',
|
||||
cnr_id: 'comfy-core',
|
||||
ver: '0.3.73',
|
||||
enableTabs: false,
|
||||
tabWidth: 65,
|
||||
tabXOffset: 10,
|
||||
hasSecondTab: false,
|
||||
secondTabText: 'Send Back',
|
||||
secondTabOffset: 80,
|
||||
secondTabWidth: 65
|
||||
},
|
||||
widgets_values: ['v1-5-pruned-emaonly-fp16.safetensors']
|
||||
widgets_values: [
|
||||
'low quality, bad anatomy, extra digits, missing digits, extra limbs, missing limbs'
|
||||
]
|
||||
}
|
||||
],
|
||||
links: [
|
||||
[1, 4, 0, 3, 0, 'MODEL'],
|
||||
[2, 5, 0, 3, 3, 'LATENT'],
|
||||
[3, 4, 1, 6, 0, 'CLIP'],
|
||||
[4, 6, 0, 3, 1, 'CONDITIONING'],
|
||||
[5, 4, 1, 7, 0, 'CLIP'],
|
||||
[6, 7, 0, 3, 2, 'CONDITIONING'],
|
||||
[7, 3, 0, 8, 0, 'LATENT'],
|
||||
[8, 4, 2, 8, 1, 'VAE'],
|
||||
[9, 8, 0, 9, 0, 'IMAGE']
|
||||
[72, 66, 0, 69, 0, 'MODEL'],
|
||||
[73, 70, 0, 65, 0, 'LATENT'],
|
||||
[74, 63, 0, 65, 1, 'VAE'],
|
||||
[75, 69, 0, 70, 0, 'MODEL'],
|
||||
[76, 67, 0, 70, 1, 'CONDITIONING'],
|
||||
[78, 68, 0, 70, 3, 'LATENT'],
|
||||
[79, 62, 0, 67, 0, 'CLIP'],
|
||||
[80, 65, 0, 9, 0, 'IMAGE'],
|
||||
[81, 62, 0, 71, 0, 'CLIP'],
|
||||
[82, 71, 0, 70, 2, 'CONDITIONING']
|
||||
],
|
||||
groups: [],
|
||||
config: {},
|
||||
extra: {
|
||||
ds: {
|
||||
offset: [0, 0],
|
||||
scale: 1
|
||||
}
|
||||
scale: 0.8,
|
||||
offset: [493.2835661399886, 100.22932409739724]
|
||||
},
|
||||
frontendVersion: '1.46.13',
|
||||
workflowRendererVersion: 'LG',
|
||||
VHS_latentpreview: false,
|
||||
VHS_latentpreviewrate: 0,
|
||||
VHS_MetadataImage: true,
|
||||
VHS_KeepIntermediate: true
|
||||
},
|
||||
version: 0.4
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user