Submodule litegraph updated: db6a916757...cd4f68ef42
@@ -33,7 +33,7 @@
|
|||||||
"svelte-check": "^3.2.0",
|
"svelte-check": "^3.2.0",
|
||||||
"svelte-dnd-action": "^0.9.22",
|
"svelte-dnd-action": "^0.9.22",
|
||||||
"typescript": "^5.0.3",
|
"typescript": "^5.0.3",
|
||||||
"vite": "^4.3.1",
|
"vite": "^4.3.8",
|
||||||
"vite-plugin-glsl": "^1.1.2",
|
"vite-plugin-glsl": "^1.1.2",
|
||||||
"vite-plugin-static-copy": "^0.14.0",
|
"vite-plugin-static-copy": "^0.14.0",
|
||||||
"vite-plugin-svelte-console-remover": "^1.0.10",
|
"vite-plugin-svelte-console-remover": "^1.0.10",
|
||||||
@@ -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",
|
||||||
@@ -80,6 +81,7 @@
|
|||||||
"tailwindcss": "^3.3.1",
|
"tailwindcss": "^3.3.1",
|
||||||
"typed-emitter": "github:andywer/typed-emitter",
|
"typed-emitter": "github:andywer/typed-emitter",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vite-plugin-full-reload": "^1.0.5"
|
"vite-plugin-full-reload": "^1.0.5",
|
||||||
|
"zod": "^3.21.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
196
pnpm-lock.yaml
generated
196
pnpm-lock.yaml
generated
@@ -69,10 +69,13 @@ importers:
|
|||||||
version: link:litegraph/packages/tsconfig
|
version: link:litegraph/packages/tsconfig
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1(svelte@3.58.0)(vite@4.3.1)
|
version: 2.1.1(svelte@3.58.0)(vite@4.3.8)
|
||||||
'@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
|
||||||
@@ -120,7 +123,10 @@ importers:
|
|||||||
version: 9.0.0
|
version: 9.0.0
|
||||||
vite-plugin-full-reload:
|
vite-plugin-full-reload:
|
||||||
specifier: ^1.0.5
|
specifier: ^1.0.5
|
||||||
version: 1.0.5(vite@4.3.1)
|
version: 1.0.5(vite@4.3.8)
|
||||||
|
zod:
|
||||||
|
specifier: ^3.21.4
|
||||||
|
version: 3.21.4
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@floating-ui/core':
|
'@floating-ui/core':
|
||||||
specifier: ^1.2.6
|
specifier: ^1.2.6
|
||||||
@@ -168,20 +174,20 @@ importers:
|
|||||||
specifier: ^5.0.3
|
specifier: ^5.0.3
|
||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^4.3.1
|
specifier: ^4.3.8
|
||||||
version: 4.3.1(sass@1.61.0)
|
version: 4.3.8(sass@1.61.0)
|
||||||
vite-plugin-glsl:
|
vite-plugin-glsl:
|
||||||
specifier: ^1.1.2
|
specifier: ^1.1.2
|
||||||
version: 1.1.2(vite@4.3.1)
|
version: 1.1.2(vite@4.3.8)
|
||||||
vite-plugin-static-copy:
|
vite-plugin-static-copy:
|
||||||
specifier: ^0.14.0
|
specifier: ^0.14.0
|
||||||
version: 0.14.0(vite@4.3.1)
|
version: 0.14.0(vite@4.3.8)
|
||||||
vite-plugin-svelte-console-remover:
|
vite-plugin-svelte-console-remover:
|
||||||
specifier: ^1.0.10
|
specifier: ^1.0.10
|
||||||
version: 1.0.10(sass@1.61.0)
|
version: 1.0.10(sass@1.61.0)
|
||||||
vite-tsconfig-paths:
|
vite-tsconfig-paths:
|
||||||
specifier: ^4.0.8
|
specifier: ^4.0.8
|
||||||
version: 4.0.8(typescript@5.0.3)(vite@4.3.1)
|
version: 4.0.8(typescript@5.0.3)(vite@4.3.8)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^0.27.3
|
specifier: ^0.27.3
|
||||||
version: 0.27.3(happy-dom@9.18.3)(jsdom@22.0.0)(sass@1.61.0)
|
version: 0.27.3(happy-dom@9.18.3)(jsdom@22.0.0)(sass@1.61.0)
|
||||||
@@ -3038,7 +3044,7 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@sveltejs/vite-plugin-svelte@2.1.1(svelte@3.58.0)(vite@4.3.1):
|
/@sveltejs/vite-plugin-svelte@2.1.1(svelte@3.58.0)(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==}
|
resolution: {integrity: sha512-7YeBDt4us0FiIMNsVXxyaP4Hwyn2/v9x3oqStkHU3ZdIc5O22pGwUwH33wUqYo+7Itdmo8zxJ45Qvfm3H7UUjQ==}
|
||||||
engines: {node: ^14.18.0 || >= 16}
|
engines: {node: ^14.18.0 || >= 16}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3051,8 +3057,8 @@ packages:
|
|||||||
magic-string: 0.30.0
|
magic-string: 0.30.0
|
||||||
svelte: 3.58.0
|
svelte: 3.58.0
|
||||||
svelte-hmr: 0.15.1(svelte@3.58.0)
|
svelte-hmr: 0.15.1(svelte@3.58.0)
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
vitefu: 0.2.4(vite@4.3.1)
|
vitefu: 0.2.4(vite@4.3.8)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@@ -3060,7 +3066,7 @@ packages:
|
|||||||
/@swc/helpers@0.4.14:
|
/@swc/helpers@0.4.14:
|
||||||
resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==}
|
resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@tootallnate/once@2.0.0:
|
/@tootallnate/once@2.0.0:
|
||||||
@@ -3126,10 +3132,14 @@ packages:
|
|||||||
/@types/chai-subset@1.3.3:
|
/@types/chai-subset@1.3.3:
|
||||||
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
|
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/chai': 4.3.4
|
'@types/chai': 4.3.5
|
||||||
|
|
||||||
/@types/chai@4.3.4:
|
/@types/chai@4.3.4:
|
||||||
resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
|
resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/chai@4.3.5:
|
||||||
|
resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==}
|
||||||
|
|
||||||
/@types/concat-stream@1.6.1:
|
/@types/concat-stream@1.6.1:
|
||||||
resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==}
|
resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==}
|
||||||
@@ -3368,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:
|
||||||
@@ -3510,7 +3528,7 @@ packages:
|
|||||||
engines: {node: '>=16.1.0'}
|
engines: {node: '>=16.1.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/autoprefixer@10.4.2(postcss@8.4.21):
|
/autoprefixer@10.4.2(postcss@8.4.21):
|
||||||
@@ -3682,7 +3700,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
fast-unique-numbers: 8.0.0
|
fast-unique-numbers: 8.0.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
worker-factory: 7.0.0
|
worker-factory: 7.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -3691,8 +3709,8 @@ packages:
|
|||||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
caniuse-lite: 1.0.30001481
|
caniuse-lite: 1.0.30001488
|
||||||
electron-to-chromium: 1.4.371
|
electron-to-chromium: 1.4.400
|
||||||
node-releases: 2.0.10
|
node-releases: 2.0.10
|
||||||
update-browserslist-db: 1.0.11(browserslist@4.21.5)
|
update-browserslist-db: 1.0.11(browserslist@4.21.5)
|
||||||
|
|
||||||
@@ -3753,6 +3771,10 @@ packages:
|
|||||||
|
|
||||||
/caniuse-lite@1.0.30001481:
|
/caniuse-lite@1.0.30001481:
|
||||||
resolution: {integrity: sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==}
|
resolution: {integrity: sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/caniuse-lite@1.0.30001488:
|
||||||
|
resolution: {integrity: sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==}
|
||||||
|
|
||||||
/case@1.6.3:
|
/case@1.6.3:
|
||||||
resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==}
|
resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==}
|
||||||
@@ -3953,7 +3975,7 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
dashify: 2.0.0
|
dashify: 2.0.0
|
||||||
indefinite-article: 0.0.2
|
indefinite-article: 0.0.2
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/compilerr@11.0.0:
|
/compilerr@11.0.0:
|
||||||
@@ -3963,7 +3985,7 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
dashify: 2.0.0
|
dashify: 2.0.0
|
||||||
indefinite-article: 0.0.2
|
indefinite-article: 0.0.2
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/concat-map@0.0.1:
|
/concat-map@0.0.1:
|
||||||
@@ -4449,8 +4471,8 @@ packages:
|
|||||||
sigmund: 1.0.1
|
sigmund: 1.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/electron-to-chromium@1.4.371:
|
/electron-to-chromium@1.4.400:
|
||||||
resolution: {integrity: sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==}
|
resolution: {integrity: sha512-Lsvf7cvwbIxCfB8VqbnVtEsjGi3+48ejDiQZfWo5gkT+1vQ2DHQI5pl0nUvPD6z1IQk6JgFeMC5ZQJqVhalEHg==}
|
||||||
|
|
||||||
/emittery@0.13.1:
|
/emittery@0.13.1:
|
||||||
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
|
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
|
||||||
@@ -4950,14 +4972,14 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
broker-factory: 3.0.76
|
broker-factory: 3.0.76
|
||||||
extendable-media-recorder-wav-encoder-worker: 8.0.77
|
extendable-media-recorder-wav-encoder-worker: 8.0.77
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/extendable-media-recorder-wav-encoder-worker@8.0.77:
|
/extendable-media-recorder-wav-encoder-worker@8.0.77:
|
||||||
resolution: {integrity: sha512-9g9Q7fhOxPY7RALHVTK9Wjnc8RPYjJ9XCBP1TaNtDraIAFxvhBRax9QUOmFqHM2MvRM6hQhNav7jn23yy6tcVQ==}
|
resolution: {integrity: sha512-9g9Q7fhOxPY7RALHVTK9Wjnc8RPYjJ9XCBP1TaNtDraIAFxvhBRax9QUOmFqHM2MvRM6hQhNav7jn23yy6tcVQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
worker-factory: 7.0.0
|
worker-factory: 7.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -5020,7 +5042,7 @@ packages:
|
|||||||
engines: {node: '>=14.15.4'}
|
engines: {node: '>=14.15.4'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/fast-unique-numbers@8.0.0:
|
/fast-unique-numbers@8.0.0:
|
||||||
@@ -5028,7 +5050,7 @@ packages:
|
|||||||
engines: {node: '>=16.1.0'}
|
engines: {node: '>=16.1.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/fastq@1.15.0:
|
/fastq@1.15.0:
|
||||||
@@ -6624,7 +6646,7 @@ packages:
|
|||||||
broker-factory: 3.0.76
|
broker-factory: 3.0.76
|
||||||
fast-unique-numbers: 8.0.0
|
fast-unique-numbers: 8.0.0
|
||||||
media-encoder-host-worker: 9.1.1
|
media-encoder-host-worker: 9.1.1
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/media-encoder-host-worker@9.1.1:
|
/media-encoder-host-worker@9.1.1:
|
||||||
@@ -6632,7 +6654,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
extendable-media-recorder-wav-encoder-broker: 7.0.78
|
extendable-media-recorder-wav-encoder-broker: 7.0.78
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
worker-factory: 7.0.0
|
worker-factory: 7.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -6642,7 +6664,7 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
media-encoder-host-broker: 7.0.79
|
media-encoder-host-broker: 7.0.79
|
||||||
media-encoder-host-worker: 9.1.1
|
media-encoder-host-worker: 9.1.1
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/merge-stream@2.0.0:
|
/merge-stream@2.0.0:
|
||||||
@@ -6760,7 +6782,7 @@ packages:
|
|||||||
engines: {node: '>=12.20.1'}
|
engines: {node: '>=12.20.1'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/murmurhash-js@1.0.0:
|
/murmurhash-js@1.0.0:
|
||||||
@@ -7176,6 +7198,14 @@ packages:
|
|||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
|
|
||||||
|
/postcss@8.4.23:
|
||||||
|
resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.6
|
||||||
|
picocolors: 1.0.0
|
||||||
|
source-map-js: 1.0.2
|
||||||
|
|
||||||
/posthtml-parser@0.10.2:
|
/posthtml-parser@0.10.2:
|
||||||
resolution: {integrity: sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==}
|
resolution: {integrity: sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -7360,7 +7390,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-oiiS2sp6eMxkvjt13yetSYUJvnAxBZk60mIxz0Vf/2lDWa/4svCyMLHIDzYKbHahkISd0UYyqLS9dI7xDlUOCA==}
|
resolution: {integrity: sha512-oiiS2sp6eMxkvjt13yetSYUJvnAxBZk60mIxz0Vf/2lDWa/4svCyMLHIDzYKbHahkISd0UYyqLS9dI7xDlUOCA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/recorder-audio-worklet@5.1.39:
|
/recorder-audio-worklet@5.1.39:
|
||||||
@@ -7372,7 +7402,7 @@ packages:
|
|||||||
recorder-audio-worklet-processor: 4.2.21
|
recorder-audio-worklet-processor: 4.2.21
|
||||||
standardized-audio-context: 25.3.45
|
standardized-audio-context: 25.3.45
|
||||||
subscribable-things: 2.1.14
|
subscribable-things: 2.1.14
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
worker-factory: 6.0.76
|
worker-factory: 6.0.76
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
@@ -7513,11 +7543,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw==}
|
resolution: {integrity: sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/rxjs@7.8.0:
|
/rxjs@7.8.1:
|
||||||
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
|
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -7755,7 +7785,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
automation-events: 6.0.0
|
automation-events: 6.0.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/std-env@3.3.3:
|
/std-env@3.3.3:
|
||||||
@@ -7839,7 +7869,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
rxjs-interop: 2.0.0
|
rxjs-interop: 2.0.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/sucrase@3.32.0:
|
/sucrase@3.32.0:
|
||||||
@@ -8314,6 +8344,11 @@ packages:
|
|||||||
|
|
||||||
/tinybench@2.4.0:
|
/tinybench@2.4.0:
|
||||||
resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==}
|
resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/tinybench@2.5.0:
|
||||||
|
resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tinypool@0.3.1:
|
/tinypool@0.3.1:
|
||||||
resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==}
|
resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==}
|
||||||
@@ -8420,6 +8455,10 @@ packages:
|
|||||||
/tslib@2.5.0:
|
/tslib@2.5.0:
|
||||||
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
|
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
|
||||||
|
|
||||||
|
/tslib@2.5.1:
|
||||||
|
resolution: {integrity: sha512-KaI6gPil5m9vF7DKaoXxx1ia9fxS4qG5YveErRRVknPDXXriu5M8h48YRjB6h5ZUOKuAKlSJYb0GaDe8I39fRw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tsutils@3.21.0(typescript@5.0.3):
|
/tsutils@3.21.0(typescript@5.0.3):
|
||||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -8597,7 +8636,7 @@ packages:
|
|||||||
fast-json-patch: 3.1.1
|
fast-json-patch: 3.1.1
|
||||||
json-stringify-pretty-compact: 3.0.0
|
json-stringify-pretty-compact: 3.0.0
|
||||||
semver: 7.4.0
|
semver: 7.4.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
vega: 5.22.1
|
vega: 5.22.1
|
||||||
vega-interpreter: 1.0.5
|
vega-interpreter: 1.0.5
|
||||||
vega-lite: 0.6.7
|
vega-lite: 0.6.7
|
||||||
@@ -8975,7 +9014,7 @@ packages:
|
|||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
vite: 4.3.1(@types/node@18.16.0)(sass@1.61.0)
|
vite: 4.3.8(@types/node@18.16.0)(sass@1.61.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
@@ -8996,7 +9035,7 @@ packages:
|
|||||||
mlly: 1.2.1
|
mlly: 1.2.1
|
||||||
pathe: 1.1.0
|
pathe: 1.1.0
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
vite: 4.3.1(@types/node@18.16.0)
|
vite: 4.3.8(@types/node@18.16.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
@@ -9082,29 +9121,29 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vite-plugin-full-reload@1.0.5(vite@4.3.1):
|
/vite-plugin-full-reload@1.0.5(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-kVZFDFWr0DxiHn6MuDVTQf7gnWIdETGlZh0hvTiMXzRN80vgF4PKbONSq8U1d0WtHsKaFODTQgJeakLacoPZEQ==}
|
resolution: {integrity: sha512-kVZFDFWr0DxiHn6MuDVTQf7gnWIdETGlZh0hvTiMXzRN80vgF4PKbONSq8U1d0WtHsKaFODTQgJeakLacoPZEQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^2 || ^3 || ^4
|
vite: ^2 || ^3 || ^4
|
||||||
dependencies:
|
dependencies:
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vite-plugin-glsl@1.1.2(vite@4.3.1):
|
/vite-plugin-glsl@1.1.2(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-zmXsfc1vn2MlYve9t3FAoWuhLyoCkNS1TuQL+TkXZL7tGmBjRErp10eNYxcse5tK9oUC5MyJpNc4ElpQnx8DoA==}
|
resolution: {integrity: sha512-zmXsfc1vn2MlYve9t3FAoWuhLyoCkNS1TuQL+TkXZL7tGmBjRErp10eNYxcse5tK9oUC5MyJpNc4ElpQnx8DoA==}
|
||||||
engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}
|
engines: {node: '>= 16.15.1', npm: '>= 8.11.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^3.0.0 || ^4.0.0
|
vite: ^3.0.0 || ^4.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/pluginutils': 5.0.2
|
'@rollup/pluginutils': 5.0.2
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-static-copy@0.14.0(vite@4.3.1):
|
/vite-plugin-static-copy@0.14.0(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-RMFmb4czomcrsbQBiUZs9HcDGN3kxGvF+OrtkfTVocp12CuoUCuJQhcY26RK35A6KS4WasGzEwcYZqHMjkAvVw==}
|
resolution: {integrity: sha512-RMFmb4czomcrsbQBiUZs9HcDGN3kxGvF+OrtkfTVocp12CuoUCuJQhcY26RK35A6KS4WasGzEwcYZqHMjkAvVw==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -9114,7 +9153,7 @@ packages:
|
|||||||
fast-glob: 3.2.12
|
fast-glob: 3.2.12
|
||||||
fs-extra: 11.1.1
|
fs-extra: 11.1.1
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-svelte-console-remover@1.0.10(sass@1.61.0):
|
/vite-plugin-svelte-console-remover@1.0.10(sass@1.61.0):
|
||||||
@@ -9130,7 +9169,7 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-tsconfig-paths@4.0.8(typescript@5.0.3)(vite@4.3.1):
|
/vite-tsconfig-paths@4.0.8(typescript@5.0.3)(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-p04zH+Ey+NT78571x0pdX7nVRIJSlmKVvYryFglSWOK3Hc72eDL0+JJfbyQiugaIBApJkaEqbBQvqpsFZOSVGg==}
|
resolution: {integrity: sha512-p04zH+Ey+NT78571x0pdX7nVRIJSlmKVvYryFglSWOK3Hc72eDL0+JJfbyQiugaIBApJkaEqbBQvqpsFZOSVGg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: '*'
|
vite: '*'
|
||||||
@@ -9141,7 +9180,7 @@ packages:
|
|||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
globrex: 0.1.2
|
globrex: 0.1.2
|
||||||
tsconfck: 2.1.1(typescript@5.0.3)
|
tsconfck: 2.1.1(typescript@5.0.3)
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
@@ -9293,8 +9332,8 @@ packages:
|
|||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vite@4.3.1(@types/node@18.16.0)(sass@1.61.0):
|
/vite@4.3.8(@types/node@18.16.0):
|
||||||
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -9320,15 +9359,48 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.16.0
|
'@types/node': 18.16.0
|
||||||
esbuild: 0.17.18
|
esbuild: 0.17.18
|
||||||
postcss: 8.4.21
|
postcss: 8.4.23
|
||||||
|
rollup: 3.21.0
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/vite@4.3.8(@types/node@18.16.0)(sass@1.61.0):
|
||||||
|
resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==}
|
||||||
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': '>= 14'
|
||||||
|
less: '*'
|
||||||
|
sass: '*'
|
||||||
|
stylus: '*'
|
||||||
|
sugarss: '*'
|
||||||
|
terser: ^5.4.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
less:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
stylus:
|
||||||
|
optional: true
|
||||||
|
sugarss:
|
||||||
|
optional: true
|
||||||
|
terser:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 18.16.0
|
||||||
|
esbuild: 0.17.18
|
||||||
|
postcss: 8.4.23
|
||||||
rollup: 3.21.0
|
rollup: 3.21.0
|
||||||
sass: 1.61.0
|
sass: 1.61.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@4.3.1(sass@1.61.0):
|
/vite@4.3.8(sass@1.61.0):
|
||||||
resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==}
|
resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -9353,7 +9425,7 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.17.18
|
esbuild: 0.17.18
|
||||||
postcss: 8.4.21
|
postcss: 8.4.23
|
||||||
rollup: 3.21.0
|
rollup: 3.21.0
|
||||||
sass: 1.61.0
|
sass: 1.61.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -9368,7 +9440,7 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vitefu@0.2.4(vite@4.3.1):
|
/vitefu@0.2.4(vite@4.3.8):
|
||||||
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^3.0.0 || ^4.0.0
|
vite: ^3.0.0 || ^4.0.0
|
||||||
@@ -9376,7 +9448,7 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 4.3.1(sass@1.61.0)
|
vite: 4.3.8(sass@1.61.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/vitest@0.27.3(happy-dom@9.18.3)(jsdom@22.0.0)(sass@1.61.0):
|
/vitest@0.27.3(happy-dom@9.18.3)(jsdom@22.0.0)(sass@1.61.0):
|
||||||
@@ -9401,7 +9473,7 @@ packages:
|
|||||||
jsdom:
|
jsdom:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/chai': 4.3.4
|
'@types/chai': 4.3.5
|
||||||
'@types/chai-subset': 1.3.3
|
'@types/chai-subset': 1.3.3
|
||||||
'@types/node': 18.16.0
|
'@types/node': 18.16.0
|
||||||
acorn: 8.8.2
|
acorn: 8.8.2
|
||||||
@@ -9416,10 +9488,10 @@ packages:
|
|||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
std-env: 3.3.3
|
std-env: 3.3.3
|
||||||
strip-literal: 1.0.1
|
strip-literal: 1.0.1
|
||||||
tinybench: 2.4.0
|
tinybench: 2.5.0
|
||||||
tinypool: 0.3.1
|
tinypool: 0.3.1
|
||||||
tinyspy: 1.1.1
|
tinyspy: 1.1.1
|
||||||
vite: 4.3.1(@types/node@18.16.0)(sass@1.61.0)
|
vite: 4.3.8(@types/node@18.16.0)(sass@1.61.0)
|
||||||
vite-node: 0.27.3(@types/node@18.16.0)(sass@1.61.0)
|
vite-node: 0.27.3(@types/node@18.16.0)(sass@1.61.0)
|
||||||
why-is-node-running: 2.2.2
|
why-is-node-running: 2.2.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -9625,7 +9697,7 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
compilerr: 10.0.2
|
compilerr: 10.0.2
|
||||||
fast-unique-numbers: 7.0.2
|
fast-unique-numbers: 7.0.2
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/worker-factory@7.0.0:
|
/worker-factory@7.0.0:
|
||||||
@@ -9634,7 +9706,7 @@ packages:
|
|||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
compilerr: 11.0.0
|
compilerr: 11.0.0
|
||||||
fast-unique-numbers: 8.0.0
|
fast-unique-numbers: 8.0.0
|
||||||
tslib: 2.5.0
|
tslib: 2.5.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/wrap-ansi@7.0.0:
|
/wrap-ansi@7.0.0:
|
||||||
@@ -9752,10 +9824,14 @@ packages:
|
|||||||
commander: 9.5.0
|
commander: 9.5.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/zod@3.21.4:
|
||||||
|
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
github.com/andywer/typed-emitter/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4:
|
github.com/andywer/typed-emitter/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4:
|
||||||
resolution: {tarball: https://codeload.github.com/andywer/typed-emitter/tar.gz/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4}
|
resolution: {tarball: https://codeload.github.com/andywer/typed-emitter/tar.gz/9a139b6fa0ec6b0db6141b5b756b784e4f7ef4e4}
|
||||||
name: typed-emitter
|
name: typed-emitter
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
rxjs: 7.8.0
|
rxjs: 7.8.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|||||||
263
src/lib/ComfyBoxStdPrompt.ts
Normal file
263
src/lib/ComfyBoxStdPrompt.ts
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
import { z, type ZodTypeAny } from "zod"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This metadata can be attached to each entry in a group to assist in
|
||||||
|
* identifying the correct nodes to apply it to.
|
||||||
|
*
|
||||||
|
* As an example, positive and negative conditioning are deployed as two
|
||||||
|
* separate nodes in ComfyUI. This makes bundling them into a { positive,
|
||||||
|
* negative } entry difficult as either one can be missing. So instead they're
|
||||||
|
* tagged like
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* conditioning: [
|
||||||
|
* { text: "masterpiece", "$meta": { types: ["positive"] } },
|
||||||
|
* { text: "worst quality", "$meta": { types: ["negative"] } },
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* The reasoning is the "types" information isn't required to reinstantiate
|
||||||
|
* the node, it's only semantic information describing how the node is used in
|
||||||
|
* the encompassing workflow. When the prompt is loaded the workflow can be
|
||||||
|
* searched for a node with the compatible type to attach the information to.
|
||||||
|
*/
|
||||||
|
const GroupMetadata = z.object({
|
||||||
|
types: z.array(z.string()).nonempty().optional()
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupMetadata = z.infer<typeof GroupMetadata>
|
||||||
|
|
||||||
|
const group = (obj: Record<string, any>): 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<typeof GroupConditioning>
|
||||||
|
|
||||||
|
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<typeof GroupCheckpoint>
|
||||||
|
|
||||||
|
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<typeof GroupVAE>
|
||||||
|
|
||||||
|
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<typeof GroupKSampler>
|
||||||
|
|
||||||
|
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<typeof GroupLatentImage>
|
||||||
|
|
||||||
|
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<typeof GroupLatentUpscale>
|
||||||
|
|
||||||
|
const GroupSDUpscale = group({
|
||||||
|
upscaler: z.string(),
|
||||||
|
overlap: z.number(),
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupSDUpscale = z.infer<typeof GroupSDUpscale>
|
||||||
|
|
||||||
|
const GroupSelfAttentionGuidance = group({
|
||||||
|
guidance_scale: z.number(),
|
||||||
|
mask_threshold: z.number(),
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupSelfAttentionGuidance = z.infer<typeof GroupSelfAttentionGuidance>
|
||||||
|
|
||||||
|
const GroupHypernetwork = group({
|
||||||
|
model_name: z.string(),
|
||||||
|
model_hashes: ModelHashes.optional(),
|
||||||
|
strength: z.number()
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupHypernetwork = z.infer<typeof GroupHypernetwork>
|
||||||
|
|
||||||
|
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<typeof GroupLoRA>
|
||||||
|
|
||||||
|
const GroupControlNet = group({
|
||||||
|
model: z.string(),
|
||||||
|
model_hashes: ModelHashes.optional(),
|
||||||
|
strength: z.number(),
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupControlNet = z.infer<typeof GroupControlNet>
|
||||||
|
|
||||||
|
const GroupCLIP = group({
|
||||||
|
clip_skip: z.number().optional()
|
||||||
|
})
|
||||||
|
export type ComfyBoxStdGroupCLIP = z.infer<typeof GroupCLIP>
|
||||||
|
|
||||||
|
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<typeof GroupDynamicThresholding>
|
||||||
|
|
||||||
|
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<typeof GroupAestheticEmbedding>
|
||||||
|
|
||||||
|
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<typeof GroupDDetailer>
|
||||||
|
|
||||||
|
const groupArray = (entry: ZodTypeAny) => {
|
||||||
|
return z.optional(z.array(entry).nonempty());
|
||||||
|
}
|
||||||
|
|
||||||
|
const Parameters = z.object({
|
||||||
|
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<typeof Parameters>
|
||||||
|
|
||||||
|
const ComfyBoxExtraData = z.object({
|
||||||
|
workflows: z.array(z.string())
|
||||||
|
})
|
||||||
|
|
||||||
|
const A1111ExtraData = z.object({
|
||||||
|
params: z.any()
|
||||||
|
})
|
||||||
|
|
||||||
|
const ExtraData = z.object({
|
||||||
|
comfybox: ComfyBoxExtraData.optional(),
|
||||||
|
a1111: A1111ExtraData.optional()
|
||||||
|
})
|
||||||
|
|
||||||
|
const Metadata = z.object({
|
||||||
|
created_with: z.string(),
|
||||||
|
author: z.string().optional(),
|
||||||
|
app_version: z.string().optional(),
|
||||||
|
commit_hash: z.string().optional(),
|
||||||
|
extra_data: ExtraData
|
||||||
|
})
|
||||||
|
|
||||||
|
const ComfyBoxStdPrompt = z.object({
|
||||||
|
version: z.number(),
|
||||||
|
metadata: Metadata,
|
||||||
|
parameters: Parameters
|
||||||
|
})
|
||||||
|
|
||||||
|
export default ComfyBoxStdPrompt
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A standardized Stable Diffusion parameter format that should be used with an
|
||||||
|
* encompassing workflow. Aims to encompass an arbitrary number of parameter
|
||||||
|
* counts and types, so that most ComfyUI workflows can have parts of their
|
||||||
|
* prompts transferred between each other.
|
||||||
|
*
|
||||||
|
* This format does *not* describe how the information should be used in the
|
||||||
|
* underlying workflow, i.e. it does not specify the structure of a ComfyUI
|
||||||
|
* execution graph. It only gives hints via tagged input types on each input
|
||||||
|
* entry as to where the data should be inserted. To recreate a ComfyBox
|
||||||
|
* workflow with the exact state of the UI intact, the `SerializedAppState` type
|
||||||
|
* should be used instead. It suffices to embed data of that type in the output
|
||||||
|
* PNGs for recreating their workflows. This type is meant as an interchange
|
||||||
|
* format *between* workflows so their inputs can be copied to and from each
|
||||||
|
* other in a sane-enough manner. (In ComfyBox, copying workflow outputs like
|
||||||
|
* images to other workflows is handled separately, since this type does not
|
||||||
|
* retain the actual image data.)
|
||||||
|
*
|
||||||
|
* In contrast with a serialized workflow, which is concerned with the
|
||||||
|
* connections between nodes and the state of the frontend's UI, this format
|
||||||
|
* concerns itself with the exact values that the execution backend receives,
|
||||||
|
* after the data in the UI have finished processing.
|
||||||
|
*
|
||||||
|
* (Take for example a "scale by" slider that adjusts the width and height of an
|
||||||
|
* img2img input image of 512 x 512 resolution by 2x. The backend will only
|
||||||
|
* "see" width 1024 and height 1024, even though the only parameter exposed from
|
||||||
|
* the frontend was the scale of 2.)
|
||||||
|
*/
|
||||||
|
export type ComfyBoxStdPrompt = z.infer<typeof ComfyBoxStdPrompt>
|
||||||
55
src/lib/ComfyBoxStdPromptSerializer.ts
Normal file
55
src/lib/ComfyBoxStdPromptSerializer.ts
Normal file
@@ -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<string, ComfyPromptConverter> = {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -98,7 +98,7 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (color) {
|
if (color) {
|
||||||
this.drawNodeOutline(node, ctx, size, fgColor, bgColor, color, thickness)
|
this.drawNodeOutline(node, ctx, size, mouseOver, fgColor, bgColor, color, thickness)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRunningNode && state.progress) {
|
if (isRunningNode && state.progress) {
|
||||||
@@ -108,27 +108,36 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private drawNodeOutline(node: LGraphNode, ctx: CanvasRenderingContext2D, size: Vector2, fgColor: string, bgColor: string, outlineColor: string, outlineThickness: number) {
|
private drawNodeOutline(node: LGraphNode, ctx: CanvasRenderingContext2D, size: Vector2, mouseOver: boolean, fgColor: string, bgColor: string, outlineColor: string, outlineThickness: number) {
|
||||||
const shape = node.shape || BuiltInSlotShape.ROUND_SHAPE;
|
const shape = node.shape || BuiltInSlotShape.ROUND_SHAPE;
|
||||||
|
|
||||||
|
var render_title = true;
|
||||||
|
if (node.titleMode == TitleMode.TRANSPARENT_TITLE || node.titleMode == TitleMode.NO_TITLE) {
|
||||||
|
render_title = false;
|
||||||
|
} else if (node.titleMode == TitleMode.AUTOHIDE_TITLE && mouseOver) {
|
||||||
|
render_title = true;
|
||||||
|
}
|
||||||
|
const titleHeight = render_title ? LiteGraph.NODE_TITLE_HEIGHT : 0;
|
||||||
|
|
||||||
ctx.lineWidth = outlineThickness;
|
ctx.lineWidth = outlineThickness;
|
||||||
ctx.globalAlpha = 0.8;
|
ctx.globalAlpha = 0.8;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
if (shape == BuiltInSlotShape.BOX_SHAPE)
|
if (shape == BuiltInSlotShape.BOX_SHAPE)
|
||||||
ctx.rect(-6, -6 + LiteGraph.NODE_TITLE_HEIGHT, 12 + size[0] + 1, 12 + size[1] + LiteGraph.NODE_TITLE_HEIGHT);
|
ctx.rect(-6, -6 + titleHeight, 12 + size[0] + 1, 12 + size[1] + titleHeight);
|
||||||
else if (shape == BuiltInSlotShape.ROUND_SHAPE || (shape == BuiltInSlotShape.CARD_SHAPE && node.flags.collapsed))
|
else if (shape == BuiltInSlotShape.ROUND_SHAPE || (shape == BuiltInSlotShape.CARD_SHAPE && node.flags.collapsed))
|
||||||
ctx.roundRect(
|
ctx.roundRect(
|
||||||
-6,
|
-6,
|
||||||
-6 - LiteGraph.NODE_TITLE_HEIGHT,
|
-6 - titleHeight,
|
||||||
12 + size[0] + 1,
|
12 + size[0] + 1,
|
||||||
12 + size[1] + LiteGraph.NODE_TITLE_HEIGHT,
|
12 + size[1] + titleHeight,
|
||||||
this.round_radius * 2
|
this.round_radius * 2
|
||||||
);
|
);
|
||||||
else if (shape == BuiltInSlotShape.CARD_SHAPE)
|
else if (shape == BuiltInSlotShape.CARD_SHAPE)
|
||||||
ctx.roundRect(
|
ctx.roundRect(
|
||||||
-6,
|
-6,
|
||||||
-6 + LiteGraph.NODE_TITLE_HEIGHT,
|
-6 + titleHeight,
|
||||||
12 + size[0] + 1,
|
12 + size[0] + 1,
|
||||||
12 + size[1] + LiteGraph.NODE_TITLE_HEIGHT,
|
12 + size[1] + titleHeight,
|
||||||
this.round_radius * 2,
|
this.round_radius * 2,
|
||||||
2
|
2
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { Progress, SerializedPrompt, SerializedPromptInputs, SerializedPromptInputsAll, SerializedPromptOutputs } from "./components/ComfyApp";
|
import type { Progress, SerializedPrompt, SerializedPromptInputsForNode, SerializedPromptInputsAll, SerializedPromptOutputs } from "./components/ComfyApp";
|
||||||
import type TypedEmitter from "typed-emitter";
|
import type TypedEmitter from "typed-emitter";
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import type { ComfyImageLocation } from "$lib/utils";
|
import type { ComfyImageLocation } from "$lib/utils";
|
||||||
|
|||||||
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>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
export let isMobile: boolean = false;
|
export let isMobile: boolean = false;
|
||||||
let isOpen: Writable<boolean> | null = null;
|
let isOpen: Writable<boolean> | null = null;
|
||||||
|
|
||||||
let children: IDragItem[] | null = null;
|
let children: IDragItem[] = [];
|
||||||
const flipDurationMs = 100;
|
const flipDurationMs = 100;
|
||||||
|
|
||||||
let selectedIndex: number = 0;
|
let selectedIndex: number = 0;
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && Array.isArray(children)}
|
{#if container}
|
||||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
export let isMobile: boolean = false;
|
export let isMobile: boolean = false;
|
||||||
|
|
||||||
let attrsChanged: Writable<number> | null = null;
|
let attrsChanged: Writable<number> | null = null;
|
||||||
let children: IDragItem[] | null = null;
|
let children: IDragItem[] = [];
|
||||||
const flipDurationMs = 100;
|
const flipDurationMs = 100;
|
||||||
|
|
||||||
$: if (container) {
|
$: if (container) {
|
||||||
@@ -35,12 +35,12 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
container = null;
|
container = null;
|
||||||
children = null;
|
children = [];
|
||||||
attrsChanged = null;
|
attrsChanged = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
children = null;
|
children = [];
|
||||||
attrsChanged = null
|
attrsChanged = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && Array.isArray(children)}
|
{#if container}
|
||||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -20,14 +19,18 @@
|
|||||||
import ComfyProperties from "./ComfyProperties.svelte";
|
import ComfyProperties from "./ComfyProperties.svelte";
|
||||||
import queueState from "$lib/stores/queueState";
|
import queueState from "$lib/stores/queueState";
|
||||||
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
||||||
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 {app} />
|
||||||
</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,10 @@ 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";
|
||||||
|
import ComfyBoxStdPromptSerializer from "$lib/ComfyBoxStdPromptSerializer";
|
||||||
|
|
||||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||||
|
|
||||||
@@ -45,32 +49,68 @@ if (typeof window !== "undefined") {
|
|||||||
nodes.ComfyReroute.setDefaultTextVisibility(!!localStorage["Comfy.ComfyReroute.DefaultVisibility"]);
|
nodes.ComfyReroute.setDefaultTextVisibility(!!localStorage["Comfy.ComfyReroute.DefaultVisibility"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueueItem = { num: number, batchCount: number }
|
/*
|
||||||
|
* Queued prompt that hasn't been sent to the backend yet.
|
||||||
|
* TODO: Assumes the currently active graph will be serialized, needs to change
|
||||||
|
* for multiple loaded workflow support
|
||||||
|
*/
|
||||||
|
type QueueItem = {
|
||||||
|
num: 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.
|
||||||
|
*/
|
||||||
export type SerializedAppState = {
|
export type SerializedAppState = {
|
||||||
|
/** Program identifier, should always be "ComfyBox" */
|
||||||
createdBy: "ComfyBox",
|
createdBy: "ComfyBox",
|
||||||
|
/** Serial version, should be incremented on breaking changes */
|
||||||
version: number,
|
version: number,
|
||||||
|
/** Commit hash if found */
|
||||||
|
commitHash?: string,
|
||||||
|
/** Graph state */
|
||||||
workflow: SerializedLGraph,
|
workflow: SerializedLGraph,
|
||||||
|
/** UI state */
|
||||||
layout: SerializedLayoutState,
|
layout: SerializedLayoutState,
|
||||||
|
/** Position/offset of the canvas at the time of saving */
|
||||||
canvas: SerializedGraphCanvasState
|
canvas: SerializedGraphCanvasState
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [link origin, link index] | value */
|
/** [link_origin, link_slot_index] | input_value */
|
||||||
export type SerializedPromptInput = [ComfyNodeID, number] | any
|
export type SerializedPromptInput = [ComfyNodeID, number] | any
|
||||||
|
|
||||||
export type SerializedPromptInputs = {
|
export type SerializedPromptInputs = Record<string, SerializedPromptInput>;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A single node in the prompt and its input values.
|
||||||
|
*/
|
||||||
|
export type SerializedPromptInputsForNode = {
|
||||||
/* property name -> value or link */
|
/* property name -> value or link */
|
||||||
inputs: Record<string, SerializedPromptInput>,
|
inputs: SerializedPromptInputs,
|
||||||
class_type: string
|
class_type: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializedPromptInputsAll = Record<ComfyNodeID, SerializedPromptInputs>
|
/*
|
||||||
|
* All nodes in the graph and their input values.
|
||||||
|
*/
|
||||||
|
export type SerializedPromptInputsAll = Record<ComfyNodeID, SerializedPromptInputsForNode>
|
||||||
|
|
||||||
export type SerializedPrompt = {
|
export type SerializedPrompt = {
|
||||||
workflow: SerializedLGraph,
|
workflow: SerializedLGraph,
|
||||||
output: SerializedPromptInputsAll
|
output: SerializedPromptInputsAll
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Outputs for each node.
|
||||||
|
*/
|
||||||
export type SerializedPromptOutputs = Record<ComfyNodeID, ComfyExecutionResult>
|
export type SerializedPromptOutputs = Record<ComfyNodeID, ComfyExecutionResult>
|
||||||
|
|
||||||
export type Progress = {
|
export type Progress = {
|
||||||
@@ -78,6 +118,10 @@ export type Progress = {
|
|||||||
max: number
|
max: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A combo node and the backend node that will send an updated config over, for
|
||||||
|
* refreshing lists of model files
|
||||||
|
*/
|
||||||
type BackendComboNode = {
|
type BackendComboNode = {
|
||||||
comboNode: ComfyComboNode,
|
comboNode: ComfyComboNode,
|
||||||
comfyInput: IComfyInputSlot,
|
comfyInput: IComfyInputSlot,
|
||||||
@@ -95,20 +139,24 @@ export default class ComfyApp {
|
|||||||
nodeOutputs: Record<string, any> = {};
|
nodeOutputs: Record<string, any> = {};
|
||||||
|
|
||||||
shiftDown: boolean = false;
|
shiftDown: 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;
|
||||||
|
private stdPromptSerializer: ComfyBoxStdPromptSerializer;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.api = new ComfyAPI();
|
this.api = new ComfyAPI();
|
||||||
this.promptSerializer = new ComfyPromptSerializer();
|
this.promptSerializer = new ComfyPromptSerializer();
|
||||||
|
this.stdPromptSerializer = new ComfyBoxStdPromptSerializer();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -151,7 +199,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();
|
||||||
|
|
||||||
@@ -165,7 +212,7 @@ export default class ComfyApp {
|
|||||||
|
|
||||||
this.requestPermissions();
|
this.requestPermissions();
|
||||||
|
|
||||||
this.alreadySetup = true;
|
this.alreadySetup.set(true);
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -286,70 +333,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);
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -406,6 +411,7 @@ export default class ComfyApp {
|
|||||||
private addKeyboardHandler() {
|
private addKeyboardHandler() {
|
||||||
window.addEventListener("keydown", (e) => {
|
window.addEventListener("keydown", (e) => {
|
||||||
this.shiftDown = e.shiftKey;
|
this.shiftDown = e.shiftKey;
|
||||||
|
this.ctrlDown = e.ctrlKey;
|
||||||
|
|
||||||
// Queue prompt using ctrl or command + enter
|
// Queue prompt using ctrl or command + enter
|
||||||
if ((e.ctrlKey || e.metaKey) && (e.key === "Enter" || e.keyCode === 13 || e.keyCode === 10)) {
|
if ((e.ctrlKey || e.metaKey) && (e.key === "Enter" || e.keyCode === 13 || e.keyCode === 10)) {
|
||||||
@@ -414,6 +420,7 @@ export default class ComfyApp {
|
|||||||
});
|
});
|
||||||
window.addEventListener("keyup", (e) => {
|
window.addEventListener("keyup", (e) => {
|
||||||
this.shiftDown = e.shiftKey;
|
this.shiftDown = e.shiftKey;
|
||||||
|
this.ctrlDown = e.ctrlKey;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,7 +568,9 @@ export default class ComfyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (get(layoutState).attrs.queuePromptButtonRunWorkflow) {
|
if (get(layoutState).attrs.queuePromptButtonRunWorkflow) {
|
||||||
this.queuePrompt(0, 1);
|
// Hold control to queue at the front
|
||||||
|
const num = this.ctrlDown ? -1 : 0;
|
||||||
|
this.queuePrompt(num, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,6 +654,9 @@ export default class ComfyApp {
|
|||||||
console.debug(graphToGraphVis(this.lGraph))
|
console.debug(graphToGraphVis(this.lGraph))
|
||||||
console.debug(promptToGraphVis(p))
|
console.debug(promptToGraphVis(p))
|
||||||
|
|
||||||
|
const stdPrompt = this.stdPromptSerializer.serialize(p);
|
||||||
|
console.warn("STD", stdPrompt);
|
||||||
|
|
||||||
const extraData: ComfyBoxPromptExtraData = {
|
const extraData: ComfyBoxPromptExtraData = {
|
||||||
extra_pnginfo: {
|
extra_pnginfo: {
|
||||||
workflow: p.workflow,
|
workflow: p.workflow,
|
||||||
@@ -709,8 +721,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)
|
||||||
@@ -854,5 +876,6 @@ export default class ComfyApp {
|
|||||||
*/
|
*/
|
||||||
clean() {
|
clean() {
|
||||||
this.nodeOutputs = {};
|
this.nodeOutputs = {};
|
||||||
|
this.a1111Prompt.set(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type ComfyGraph from "$lib/ComfyGraph";
|
|||||||
import type { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
import type { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||||
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
import type ComfyGraphNode from "$lib/nodes/ComfyGraphNode";
|
||||||
import { GraphInput, GraphOutput, LGraph, LGraphNode, LLink, NodeMode, Subgraph, type SlotIndex } from "@litegraph-ts/core";
|
import { GraphInput, GraphOutput, LGraph, LGraphNode, LLink, NodeMode, Subgraph, type SlotIndex } from "@litegraph-ts/core";
|
||||||
import type { SerializedPrompt, SerializedPromptInput, SerializedPromptInputs, SerializedPromptInputsAll } from "./ComfyApp";
|
import type { SerializedPrompt, SerializedPromptInput, SerializedPromptInputsForNode, SerializedPromptInputsAll, SerializedPromptInputs } from "./ComfyApp";
|
||||||
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
import type IComfyInputSlot from "$lib/IComfyInputSlot";
|
||||||
|
|
||||||
function hasTag(node: LGraphNode, tag: string): boolean {
|
function hasTag(node: LGraphNode, tag: string): boolean {
|
||||||
@@ -113,7 +113,7 @@ export class UpstreamNodeLocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are non-target nodes between us and another
|
// If there are non-target nodes between us and another
|
||||||
// backend node, we have to traverse them first. This
|
// target node, we have to traverse them first. This
|
||||||
// behavior is dependent on the type of node. Reroute nodes
|
// behavior is dependent on the type of node. Reroute nodes
|
||||||
// will simply follow their single input, while branching
|
// will simply follow their single input, while branching
|
||||||
// nodes have conditional logic that determines which link
|
// nodes have conditional logic that determines which link
|
||||||
@@ -150,7 +150,7 @@ export class UpstreamNodeLocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class ComfyPromptSerializer {
|
export default class ComfyPromptSerializer {
|
||||||
serializeInputValues(node: ComfyBackendNode): Record<string, SerializedPromptInput> {
|
serializeInputValues(node: ComfyBackendNode): SerializedPromptInputs {
|
||||||
// Store input values passed by frontend-only nodes
|
// Store input values passed by frontend-only nodes
|
||||||
if (!node.inputs) {
|
if (!node.inputs) {
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
import { Button } from "@gradio/button";
|
import { Button } from "@gradio/button";
|
||||||
import type ComfyApp from "./ComfyApp";
|
import type ComfyApp from "./ComfyApp";
|
||||||
import { tick } from "svelte";
|
import { tick } from "svelte";
|
||||||
import Modal from "./Modal.svelte";
|
import Modal from "./Modal.svelte";
|
||||||
|
import DropZone from "./DropZone.svelte";
|
||||||
|
|
||||||
|
export let app: ComfyApp;
|
||||||
|
|
||||||
let queuePending: Writable<QueueEntry[]> | null = null;
|
let queuePending: Writable<QueueEntry[]> | null = null;
|
||||||
let queueRunning: Writable<QueueEntry[]> | null = null;
|
let queueRunning: Writable<QueueEntry[]> | null = null;
|
||||||
@@ -197,6 +200,7 @@
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<div class="queue">
|
<div class="queue">
|
||||||
|
<DropZone {app} />
|
||||||
<div class="queue-entries {mode}-mode" bind:this={queueList}>
|
<div class="queue-entries {mode}-mode" bind:this={queueList}>
|
||||||
{#if _entries.length > 0}
|
{#if _entries.length > 0}
|
||||||
{#each _entries as entry}
|
{#each _entries as entry}
|
||||||
|
|||||||
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: absolute;
|
||||||
|
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>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
export let isMobile: boolean = false;
|
export let isMobile: boolean = false;
|
||||||
|
|
||||||
let attrsChanged: Writable<boolean> | null = null;
|
let attrsChanged: Writable<boolean> | null = null;
|
||||||
let children: IDragItem[] | null = null;
|
let children: IDragItem[] = [];
|
||||||
const flipDurationMs = 100;
|
const flipDurationMs = 100;
|
||||||
|
|
||||||
let selectedIndex: number = 0;
|
let selectedIndex: number = 0;
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
attrsChanged = container.attrsChanged
|
attrsChanged = container.attrsChanged
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
children = null;
|
children = [];
|
||||||
attrsChanged = null
|
attrsChanged = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && Array.isArray(children)}
|
{#if container}
|
||||||
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
{@const selected = $uiState.uiUnlocked && $selectionState.currentSelection.includes(container.id)}
|
||||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||||
class:hide-block={container.attrs.containerVariant === "hidden"}
|
class:hide-block={container.attrs.containerVariant === "hidden"}
|
||||||
|
|||||||
377
src/lib/convertA1111ToStdPrompt.ts
Normal file
377
src/lib/convertA1111ToStdPrompt.ts
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
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] {
|
||||||
|
let name = a1111Sampler.toLowerCase().replace("++", "pp").replaceAll(" ", "_");
|
||||||
|
let scheduler = "normal";
|
||||||
|
if (name.includes("karras")) {
|
||||||
|
name = name.replace("karras", "").replace(/_+$/, "");
|
||||||
|
scheduler = "karras";
|
||||||
|
} else {
|
||||||
|
scheduler = "normal"
|
||||||
|
}
|
||||||
|
return [name, scheduler]
|
||||||
|
}
|
||||||
|
|
||||||
|
const reAddNetModelName = /^([^(]+)\((.+)\)$/;
|
||||||
|
|
||||||
|
function parseAddNetModelNameAndHash(name: string | null): [string | undefined, string | undefined] {
|
||||||
|
if (!name)
|
||||||
|
return [undefined, undefined]
|
||||||
|
|
||||||
|
const match = name.match(reAddNetModelName);
|
||||||
|
if (match != null) {
|
||||||
|
return [match[1], match[2]]
|
||||||
|
}
|
||||||
|
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 != null) {
|
||||||
|
return [match[1], match[2]]
|
||||||
|
}
|
||||||
|
return [undefined, undefined]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function convertA1111ToStdPrompt(infotext: A1111ParsedInfotext): ComfyBoxStdPrompt {
|
||||||
|
const popOpt = (name: string): string | undefined => {
|
||||||
|
const v = infotext.extraParams[name];
|
||||||
|
delete infotext.extraParams[name];
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parameters: ComfyBoxStdParameters = {}
|
||||||
|
|
||||||
|
parameters.conditioning = [
|
||||||
|
{
|
||||||
|
"$meta": {
|
||||||
|
types: ["positive"]
|
||||||
|
},
|
||||||
|
text: infotext.positive,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$meta": {
|
||||||
|
types: ["negative"]
|
||||||
|
},
|
||||||
|
text: infotext.negative,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const hrUp = popOpt("hires upscale");
|
||||||
|
const hrSz = popOpt("hires resize");
|
||||||
|
let hrScaleBy = hrUp ? parseFloat(hrUp) : undefined;
|
||||||
|
let hrMethod = popOpt("hires upscaler");
|
||||||
|
let hrSteps = popOpt("hires steps");
|
||||||
|
let hrWidth = undefined
|
||||||
|
let hrHeight = undefined
|
||||||
|
if (hrSz) {
|
||||||
|
[hrWidth, hrHeight] = hrSz.split(hrSz).map(parseInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const latent_image: ComfyBoxStdGroupLatentImage = {
|
||||||
|
width: infotext.width,
|
||||||
|
height: infotext.height,
|
||||||
|
// type: "empty", // detect txt2img???
|
||||||
|
batch_count: infotext.batchSize,
|
||||||
|
batch_pos: infotext.batchPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
const maskBlur = popOpt("mask blur")
|
||||||
|
if (maskBlur != null)
|
||||||
|
latent_image.mask_blur = parseFloat(maskBlur)
|
||||||
|
|
||||||
|
parameters.latent_image = [latent_image];
|
||||||
|
|
||||||
|
if (hrMethod != null) {
|
||||||
|
let uw, uh;
|
||||||
|
if (hrScaleBy) {
|
||||||
|
uw = infotext.width * hrScaleBy;
|
||||||
|
uh = infotext.height * hrScaleBy;
|
||||||
|
} else {
|
||||||
|
if (hrWidth == null || hrHeight == null)
|
||||||
|
throw new Error("Highres prompt didn't have width/height!")
|
||||||
|
uw = +hrWidth;
|
||||||
|
uh = +hrHeight;
|
||||||
|
}
|
||||||
|
const hr: ComfyBoxStdGroupLatentUpscale = {
|
||||||
|
width: uw,
|
||||||
|
height: uh,
|
||||||
|
upscale_by: hrScaleBy,
|
||||||
|
upscale_method: hrMethod
|
||||||
|
}
|
||||||
|
parameters.latent_upscale = [hr];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [sampler_name, scheduler] = getSamplerAndScheduler(infotext.sampler)
|
||||||
|
|
||||||
|
const k_sampler: ComfyBoxStdGroupKSampler = {
|
||||||
|
steps: infotext.steps,
|
||||||
|
seed: infotext.seed,
|
||||||
|
cfg_scale: infotext.cfgScale,
|
||||||
|
denoise: hrMethod != null ? 1.0 : infotext.denoise || 1.0, // detect img2img???
|
||||||
|
sampler_name,
|
||||||
|
scheduler,
|
||||||
|
}
|
||||||
|
parameters.k_sampler = [k_sampler];
|
||||||
|
|
||||||
|
if (hrMethod != null) {
|
||||||
|
const k_sampler_hr: ComfyBoxStdGroupKSampler = {
|
||||||
|
"$meta": {
|
||||||
|
types: ["upscale"]
|
||||||
|
},
|
||||||
|
steps: hrSteps != null ? parseInt(hrSteps) : infotext.steps,
|
||||||
|
seed: infotext.seed,
|
||||||
|
cfg_scale: infotext.cfgScale,
|
||||||
|
denoise: infotext.denoise || 1.0,
|
||||||
|
sampler_name,
|
||||||
|
scheduler,
|
||||||
|
}
|
||||||
|
parameters.k_sampler.push(k_sampler_hr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (infotext.modelHash || infotext.modelName) {
|
||||||
|
const checkpoint: ComfyBoxStdGroupCheckpoint = {
|
||||||
|
model_name: infotext.modelName,
|
||||||
|
model_hashes: {
|
||||||
|
a1111_shorthash: infotext.modelHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parameters.checkpoint = [checkpoint]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("clip skip" in infotext.extraParams) {
|
||||||
|
const clipSkip = popOpt("clip skip")
|
||||||
|
parameters.clip = [{
|
||||||
|
clip_skip: parseInt(clipSkip)
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("sd upscale upscaler" in infotext.extraParams) {
|
||||||
|
const sdUpscaleUpscaler = popOpt("sd upscale upscaler")
|
||||||
|
const sdUpscaleOverlap = popOpt("sd upscale overlap") || "64"
|
||||||
|
parameters.sd_upscale = [{
|
||||||
|
upscaler: sdUpscaleUpscaler,
|
||||||
|
overlap: parseInt(sdUpscaleOverlap)
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
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") {
|
||||||
|
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
|
||||||
|
|
||||||
|
for (const [extraNetworkType, extraNetworks] of Object.entries(infotext.extraNetworks)) {
|
||||||
|
for (const extraNetworkParams of extraNetworks) {
|
||||||
|
let strength;
|
||||||
|
switch (extraNetworkType.toLowerCase()) {
|
||||||
|
case "lora":
|
||||||
|
case "locon":
|
||||||
|
case "lyco":
|
||||||
|
strength = parseFloat(extraNetworkParams.items[1]);
|
||||||
|
const lora: ComfyBoxStdGroupLoRA = {
|
||||||
|
module_name: extraNetworkType.toLowerCase(),
|
||||||
|
model_name: extraNetworkParams.items[0],
|
||||||
|
strength_unet: strength,
|
||||||
|
strength_tenc: strength,
|
||||||
|
}
|
||||||
|
if (parameters.lora)
|
||||||
|
parameters.lora.push(lora)
|
||||||
|
else
|
||||||
|
parameters.lora = [lora]
|
||||||
|
break;
|
||||||
|
case "hypernet":
|
||||||
|
strength = parseFloat(extraNetworkParams.items[1]);
|
||||||
|
const hypernetwork: ComfyBoxStdGroupHypernetwork = {
|
||||||
|
model_name: extraNetworkParams.items[0],
|
||||||
|
strength
|
||||||
|
}
|
||||||
|
if (parameters.hypernetwork)
|
||||||
|
parameters.hypernetwork.push(hypernetwork)
|
||||||
|
else
|
||||||
|
parameters.hypernetwork = [hypernetwork]
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete infotext.extraNetworks[extraNetworkType]
|
||||||
|
}
|
||||||
|
|
||||||
|
let index = 1;
|
||||||
|
let found = infotext.extraParams[`addnet module ${index}`]
|
||||||
|
while (`addnet module ${index}` in infotext.extraParams) {
|
||||||
|
popOpt("addnet enabled")
|
||||||
|
const moduleName = popOpt(`addnet module ${index}`)
|
||||||
|
const modelName = popOpt(`addnet model ${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}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleName !== "LoRA") {
|
||||||
|
throw new Error("Unknown AddNet model type " + moduleName)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [name, hash] = parseAddNetModelNameAndHash(modelName);
|
||||||
|
if (name == null || hash == null) {
|
||||||
|
throw new Error("Error parsing addnet model name: " + JSON.stringify(modelName));
|
||||||
|
}
|
||||||
|
|
||||||
|
let shorthash = undefined
|
||||||
|
let shorthash_legacy = undefined
|
||||||
|
if (hash.length > 8) {
|
||||||
|
// new method using safetensors hash
|
||||||
|
shorthash = hash
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// old hash using webui's 0x10000 hashing method
|
||||||
|
shorthash_legacy = hash
|
||||||
|
}
|
||||||
|
|
||||||
|
const lora: ComfyBoxStdGroupLoRA = {
|
||||||
|
model_name: name,
|
||||||
|
module_name: moduleName,
|
||||||
|
model_hashes: {
|
||||||
|
addnet_shorthash: shorthash,
|
||||||
|
addnet_shorthash_legacy: shorthash_legacy
|
||||||
|
},
|
||||||
|
strength_unet: parseFloat(weightA),
|
||||||
|
strength_tenc: parseFloat(weightB),
|
||||||
|
}
|
||||||
|
if (parameters.lora)
|
||||||
|
parameters.lora.push(lora)
|
||||||
|
else
|
||||||
|
parameters.lora = [lora]
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
found = infotext.extraParams[`addnet model ${index}`]
|
||||||
|
}
|
||||||
|
|
||||||
|
let app_version = popOpt("version")
|
||||||
|
|
||||||
|
const extra_data: Record<string, any> = {};
|
||||||
|
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
|
||||||
|
},
|
||||||
|
parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn("Unhandled A1111 parameters:", infotext.extraParams, infotext.extraNetworks)
|
||||||
|
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
@@ -312,7 +312,9 @@ export class ComfyExecuteSubgraphAction extends ComfyGraphNode {
|
|||||||
if (!app)
|
if (!app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
app.queuePrompt(0, 1, tag);
|
// Hold control to queue at the front
|
||||||
|
const num = app.ctrlDown ? -1 : 0;
|
||||||
|
app.queuePrompt(num, 1, tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ export default class ComfyComboNode extends ComfyWidgetNode<string> {
|
|||||||
// Wait until the initial graph load for combo to be valid.
|
// Wait until the initial graph load for combo to be valid.
|
||||||
firstLoad: Writable<boolean>;
|
firstLoad: Writable<boolean>;
|
||||||
lightUp: Writable<boolean>;
|
lightUp: Writable<boolean>;
|
||||||
valuesForCombo: Writable<any[] | null>; // Changed when the combo box has values.
|
valuesForCombo: Writable<any[]>; // Changed when the combo box has values.
|
||||||
|
|
||||||
constructor(name?: string) {
|
constructor(name?: string) {
|
||||||
super(name, "A")
|
super(name, "A")
|
||||||
this.firstLoad = writable(false)
|
this.firstLoad = writable(false)
|
||||||
this.lightUp = writable(true)
|
this.lightUp = writable(true)
|
||||||
this.valuesForCombo = writable(null)
|
this.valuesForCombo = writable([])
|
||||||
}
|
}
|
||||||
|
|
||||||
override onPropertyChanged(property: any, value: any) {
|
override onPropertyChanged(property: any, value: any) {
|
||||||
|
|||||||
166
src/lib/parseA1111.ts
Normal file
166
src/lib/parseA1111.ts
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
interface ExtraNetworkParams {
|
||||||
|
items: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type A1111ParsedInfotext = {
|
||||||
|
positive: string,
|
||||||
|
negative: string,
|
||||||
|
|
||||||
|
steps: number,
|
||||||
|
cfgScale: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
modelHash?: string,
|
||||||
|
modelName?: string,
|
||||||
|
batchSize?: number,
|
||||||
|
batchPos?: number,
|
||||||
|
sampler: string,
|
||||||
|
seed: number,
|
||||||
|
denoise?: number,
|
||||||
|
|
||||||
|
extraNetworks: Record<string, ExtraNetworkParams[]>
|
||||||
|
extraParams: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type A1111ParsingError = {
|
||||||
|
error: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const reExtraNetworks = /<(\w+):([^>]+)>/g;
|
||||||
|
const reParam = /\s*([\w ]+):\s*("(?:\\"[^,]|\\"|\\|[^\"])+"|[^,]*)(?:,|$)/g;
|
||||||
|
|
||||||
|
function parseExtraNetworks(prompt: string): [string, Record<string, ExtraNetworkParams[]>] {
|
||||||
|
const res: Record<string, ExtraNetworkParams[]> = {};
|
||||||
|
|
||||||
|
function found(_match: string, modelType: string, args: string): string {
|
||||||
|
if (!res[modelType]) {
|
||||||
|
res[modelType] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
res[modelType].push({ items: args.split(":") });
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt = prompt.replace(reExtraNetworks, found);
|
||||||
|
|
||||||
|
return [prompt, res];
|
||||||
|
}
|
||||||
|
|
||||||
|
type A1111ParamHandler = string | ((prompt: A1111ParsedInfotext, value: string) => void);
|
||||||
|
|
||||||
|
const wrapFloat = (name: string): ((p: A1111ParsedInfotext, v: string) => void) => {
|
||||||
|
return (p, v) => {
|
||||||
|
p[name] = parseFloat(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapInt = (name: string): A1111ParamHandler => {
|
||||||
|
return (p, v) => {
|
||||||
|
p[name] = parseInt(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlers: Record<string, A1111ParamHandler> = {
|
||||||
|
steps: wrapInt("steps"),
|
||||||
|
"cfg scale": wrapFloat("cfgScale"),
|
||||||
|
"size": (p, v) => {
|
||||||
|
const [widthStr, heightStr] = v.split("x")
|
||||||
|
p.width = parseInt(widthStr);
|
||||||
|
p.height = parseInt(heightStr);
|
||||||
|
},
|
||||||
|
"model hash": "modelHash",
|
||||||
|
model: "modelName",
|
||||||
|
"batch size": wrapInt("batchSize"),
|
||||||
|
"batch pos": wrapInt("batchPos"),
|
||||||
|
sampler: "sampler",
|
||||||
|
seed: wrapInt("seed"),
|
||||||
|
"denoising strength": wrapFloat("denoise")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parses AUTOMATIC1111/stable-diffusion-webui format infotext into their raw parameters.
|
||||||
|
*
|
||||||
|
* Format is as follows:
|
||||||
|
* - Prompt text immediately starts at the start of the file, ending
|
||||||
|
* on the first line starting with "Negative prompt:" or "Steps:"
|
||||||
|
* - "Negative prompt:" is optional and might be omitted
|
||||||
|
* - Following "Steps:" are various sort-of-comma-separated values.
|
||||||
|
* Random characters can completely break parsing. Here be dragons.
|
||||||
|
*/
|
||||||
|
export default function parseA1111(infotext: string): A1111ParsedInfotext | A1111ParsingError {
|
||||||
|
let doneWithPrompt = false;
|
||||||
|
|
||||||
|
let positive_ = ""
|
||||||
|
let negative = ""
|
||||||
|
|
||||||
|
const lines = infotext.trim().split("\n")
|
||||||
|
let lastLineIdx = lines.findIndex(l => l.trim().indexOf("Steps: ") !== -1)
|
||||||
|
if (lastLineIdx === -1) {
|
||||||
|
return { error: "Steps: line not found" }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = 0; index < lastLineIdx; index++) {
|
||||||
|
let line = lines[index].trim()
|
||||||
|
if (line.startsWith("Negative prompt:")) {
|
||||||
|
doneWithPrompt = true;
|
||||||
|
line = line.substring(16).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doneWithPrompt) {
|
||||||
|
const addNewLine = negative != ""
|
||||||
|
negative += (addNewLine ? "\n" : "") + line
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const addNewLine = positive_ != ""
|
||||||
|
positive_ += (addNewLine ? "\n" : "") + line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// webui doesn't apply extra networks in the negative prompt
|
||||||
|
let [positive, extraNetworks] = parseExtraNetworks(positive_)
|
||||||
|
|
||||||
|
const extraParams: Record<string, string> = {}
|
||||||
|
|
||||||
|
let result: A1111ParsedInfotext = {
|
||||||
|
positive,
|
||||||
|
negative,
|
||||||
|
|
||||||
|
// defaults taken from webui
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
steps: 20,
|
||||||
|
cfgScale: 7.0,
|
||||||
|
seed: -1,
|
||||||
|
sampler: "Euler",
|
||||||
|
|
||||||
|
extraNetworks,
|
||||||
|
extraParams
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = lastLineIdx; index < lines.length; index++) {
|
||||||
|
const line = lines[index];
|
||||||
|
for (let [_, key, value] of line.matchAll(reParam)) {
|
||||||
|
key = key.toLowerCase()
|
||||||
|
if (value[0] === '"' && value[value.length - 1] === '""')
|
||||||
|
value = value.substring(1, value.length - 1)
|
||||||
|
|
||||||
|
const handler = handlers[key]
|
||||||
|
if (handler != null) {
|
||||||
|
if (value != null) {
|
||||||
|
if (typeof handler === "function") {
|
||||||
|
handler(result, value)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(result as any)[handler] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
extraParams[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -39,8 +39,10 @@ export type LayoutAttributes = {
|
|||||||
queuePromptButtonName: string,
|
queuePromptButtonName: string,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If true, clicking the "Queue Prompt" button will run the default subgraph.
|
* If true, clicking the "Queue Prompt" button will run the default
|
||||||
* Set this to false if you need special behavior before running any subgraphs.
|
* subgraph. Set this to false if you need special behavior before running
|
||||||
|
* any subgraphs, and instead use the `onDefaultQueueAction` event of the
|
||||||
|
* Comfy.QueueEvents node.
|
||||||
*/
|
*/
|
||||||
queuePromptButtonRunWorkflow: boolean,
|
queuePromptButtonRunWorkflow: boolean,
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,9 @@ export type LayoutState = {
|
|||||||
*/
|
*/
|
||||||
attrs: LayoutAttributes
|
attrs: LayoutAttributes
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment to force Svelte to re-render the props panel
|
||||||
|
*/
|
||||||
refreshPropsPanel: Writable<number>
|
refreshPropsPanel: Writable<number>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +107,7 @@ export type Attributes = {
|
|||||||
title: string,
|
title: string,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of classes to apply to the component.
|
* List of CSS classes to apply to the component.
|
||||||
*/
|
*/
|
||||||
classes: string,
|
classes: string,
|
||||||
|
|
||||||
@@ -204,22 +209,22 @@ export type AttributesSpec = {
|
|||||||
values?: string[],
|
values?: string[],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If `type` is "number", step for the slider
|
* If `type` is "number", step for the slider that edits this attribute
|
||||||
*/
|
*/
|
||||||
step?: number,
|
step?: number,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If `type` is "number", min for the slider
|
* If `type` is "number", min for the slider that edits this attribute
|
||||||
*/
|
*/
|
||||||
min?: number,
|
min?: number,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If `type` is "number", max for the slider
|
* If `type` is "number", max for the slider that edits this attribute
|
||||||
*/
|
*/
|
||||||
max?: number,
|
max?: number,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If `type` is "string", display as a textarea.
|
* If `type` is "string", display as a textarea instead of an input.
|
||||||
*/
|
*/
|
||||||
multiline?: boolean,
|
multiline?: boolean,
|
||||||
|
|
||||||
@@ -863,8 +868,9 @@ function nodeAdded(node: LGraphNode, options: LGraphAddNodeOptions) {
|
|||||||
let prevWidget = state.allItemsByNode[node.id]
|
let prevWidget = state.allItemsByNode[node.id]
|
||||||
if (prevWidget == null) {
|
if (prevWidget == null) {
|
||||||
// If a subgraph was cloned, try looking for the original widget node corresponding to the new widget node being added.
|
// If a subgraph was cloned, try looking for the original widget node corresponding to the new widget node being added.
|
||||||
// `node` is the new ComfyWidgetNode instance to copy attrs to.
|
// `node` is the new ComfyWidgetNode instance to copy layout attrs to.
|
||||||
// `options.cloneData` should contain the results of Subgraph.clone(), called "subgraphNewIDMapping".
|
// `options.cloneData` should contain the results of Subgraph.clone(), which is named "subgraphNewIDMapping" in an
|
||||||
|
// entry of the `forNode` Record.
|
||||||
// `options.cloneData` is attached to the onNodeAdded options if a node is added to a graph after being
|
// `options.cloneData` is attached to the onNodeAdded options if a node is added to a graph after being
|
||||||
// selection-cloned or pasted, as they both call clone() internally.
|
// selection-cloned or pasted, as they both call clone() internally.
|
||||||
const cloneData = options.cloneData.forNode[options.prevNodeID]
|
const cloneData = options.cloneData.forNode[options.prevNodeID]
|
||||||
@@ -879,7 +885,7 @@ function nodeAdded(node: LGraphNode, options: LGraphAddNodeOptions) {
|
|||||||
if (nodeIDInLayoutState) {
|
if (nodeIDInLayoutState) {
|
||||||
// Gottem.
|
// Gottem.
|
||||||
prevWidget = state.allItemsByNode[nodeIDInLayoutState]
|
prevWidget = state.allItemsByNode[nodeIDInLayoutState]
|
||||||
console.warn("FOUND CLONED SUBGRAPH NODE", node.id, "=>", nodeIDInLayoutState, prevWidget)
|
// console.warn("FOUND CLONED SUBGRAPH NODE", node.id, "=>", nodeIDInLayoutState, prevWidget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import type { ComfyExecutionResult } from "$lib/nodes/ComfyWidgetNodes";
|
|||||||
import notify from "$lib/notify";
|
import notify from "$lib/notify";
|
||||||
import { get, writable, type Writable } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
|
|
||||||
export type QueueItem = {
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type QueueEntryStatus = "success" | "error" | "interrupted" | "all_cached" | "unknown";
|
export type QueueEntryStatus = "success" | "error" | "interrupted" | "all_cached" | "unknown";
|
||||||
|
|
||||||
type QueueStateOps = {
|
type QueueStateOps = {
|
||||||
@@ -23,8 +19,13 @@ type QueueStateOps = {
|
|||||||
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: ComfyExecutionResult) => void
|
onExecuted: (promptID: PromptID, nodeID: ComfyNodeID, output: ComfyExecutionResult) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Single job that the backend keeps track of.
|
||||||
|
*/
|
||||||
export type QueueEntry = {
|
export type QueueEntry = {
|
||||||
/* Data preserved on page refresh */
|
/*** Data preserved on page refresh ***/
|
||||||
|
|
||||||
|
/** Priority of the prompt. -1 means to queue at the front. */
|
||||||
number: number,
|
number: number,
|
||||||
queuedAt?: Date,
|
queuedAt?: Date,
|
||||||
finishedAt?: Date,
|
finishedAt?: Date,
|
||||||
@@ -33,23 +34,34 @@ export type QueueEntry = {
|
|||||||
extraData: ComfyBoxPromptExtraData,
|
extraData: ComfyBoxPromptExtraData,
|
||||||
goodOutputs: ComfyNodeID[],
|
goodOutputs: ComfyNodeID[],
|
||||||
|
|
||||||
/* Data not sent by ComfyUI's API, lost on page refresh */
|
/*** Data not sent by ComfyUI's API, lost on page refresh ***/
|
||||||
|
|
||||||
/* Prompt outputs, collected while the prompt is still executing */
|
/* Prompt outputs, collected while the prompt is still executing */
|
||||||
outputs: SerializedPromptOutputs,
|
outputs: SerializedPromptOutputs,
|
||||||
|
/* Nodes of the workflow that have finished running so far. */
|
||||||
/* Nodes in of the workflow that have finished running so far. */
|
|
||||||
nodesRan: Set<ComfyNodeID>,
|
nodesRan: Set<ComfyNodeID>,
|
||||||
|
/* Nodes of the workflow the backend reported as cached. */
|
||||||
cachedNodes: Set<ComfyNodeID>
|
cachedNodes: Set<ComfyNodeID>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Represents a queue entry that has finished executing (suceeded or failed) and
|
||||||
|
* has been moved to the history.
|
||||||
|
*/
|
||||||
export type CompletedQueueEntry = {
|
export type CompletedQueueEntry = {
|
||||||
|
/** Corresponding entry in the queue, for the prompt/extra data */
|
||||||
entry: QueueEntry,
|
entry: QueueEntry,
|
||||||
|
/** The result of this prompt, success/failed/cached */
|
||||||
status: QueueEntryStatus,
|
status: QueueEntryStatus,
|
||||||
|
/** Message to display in the frontend */
|
||||||
message?: string,
|
message?: string,
|
||||||
|
/** Detailed error/stacktrace, perhaps inspectible with a popup */
|
||||||
error?: string,
|
error?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keeps track of queued and completed (history) prompts.
|
||||||
|
*/
|
||||||
export type QueueState = {
|
export type QueueState = {
|
||||||
queueRunning: Writable<QueueEntry[]>,
|
queueRunning: Writable<QueueEntry[]>,
|
||||||
queuePending: Writable<QueueEntry[]>,
|
queuePending: Writable<QueueEntry[]>,
|
||||||
@@ -57,6 +69,11 @@ export type QueueState = {
|
|||||||
queueRemaining: number | "X" | null;
|
queueRemaining: number | "X" | null;
|
||||||
runningNodeID: ComfyNodeID | null;
|
runningNodeID: ComfyNodeID | null;
|
||||||
progress: Progress | null,
|
progress: Progress | null,
|
||||||
|
/**
|
||||||
|
* If true, user pressed the "Interrupt" button in the frontend. Disable the
|
||||||
|
* button and wait until the next prompt starts running to re-enable it
|
||||||
|
* again
|
||||||
|
*/
|
||||||
isInterrupting: boolean
|
isInterrupting: boolean
|
||||||
}
|
}
|
||||||
type WritableQueueStateStore = Writable<QueueState> & QueueStateOps;
|
type WritableQueueStateStore = Writable<QueueState> & QueueStateOps;
|
||||||
@@ -159,6 +176,7 @@ function moveToCompleted(index: number, queue: Writable<QueueEntry[]>, status: Q
|
|||||||
return qc
|
return qc
|
||||||
})
|
})
|
||||||
|
|
||||||
|
state.isInterrupting = false;
|
||||||
store.set(state)
|
store.set(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,10 @@
|
|||||||
export let widget: WidgetLayout | null = null;
|
export let widget: WidgetLayout | null = null;
|
||||||
export let isMobile: boolean = false;
|
export let isMobile: boolean = false;
|
||||||
let node: ComfyComboNode | null = null;
|
let node: ComfyComboNode | null = null;
|
||||||
let nodeValue: Writable<string> | null = null;
|
let nodeValue: Writable<string> = writable("");
|
||||||
let propsChanged: Writable<number> | null = null;
|
let propsChanged: Writable<number> | null = null;
|
||||||
let lightUp: Writable<boolean> = writable(false);
|
let lightUp: Writable<boolean> = writable(false);
|
||||||
let valuesForCombo: Writable<any[]> | null = null;
|
let valuesForCombo: Writable<any[]> = writable([])
|
||||||
let lastConfigured: any = null;
|
let lastConfigured: any = null;
|
||||||
let option: any = null;
|
let option: any = null;
|
||||||
|
|
||||||
@@ -132,77 +132,69 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper comfy-combo" class:mobile={isMobile} class:updated={$lightUp}>
|
<div class="wrapper comfy-combo" class:mobile={isMobile} class:updated={$lightUp}>
|
||||||
{#key $valuesForCombo}
|
<label>
|
||||||
{#if node !== null && nodeValue !== null}
|
{#if widget.attrs.title !== ""}
|
||||||
{#if $valuesForCombo == null}
|
<BlockTitle show_label={true}>
|
||||||
<span>Loading...</span>
|
{widget.attrs.title}
|
||||||
{:else}
|
<span class="count-text">({$valuesForCombo.length})</span>
|
||||||
<label>
|
</BlockTitle>
|
||||||
{#if widget.attrs.title !== ""}
|
|
||||||
<BlockTitle show_label={true}>
|
|
||||||
{widget.attrs.title}
|
|
||||||
<span class="count-text">({$valuesForCombo.length})</span>
|
|
||||||
</BlockTitle>
|
|
||||||
{/if}
|
|
||||||
<Select
|
|
||||||
value={$nodeValue}
|
|
||||||
bind:justValue={option}
|
|
||||||
bind:hoverItemIndex
|
|
||||||
bind:filterText
|
|
||||||
bind:listOpen
|
|
||||||
bind:input
|
|
||||||
items={$valuesForCombo}
|
|
||||||
disabled={isDisabled(widget)}
|
|
||||||
clearable={false}
|
|
||||||
showChevron={true}
|
|
||||||
listAutoWidth={true}
|
|
||||||
inputAttributes={{ autocomplete: 'off' }}
|
|
||||||
on:change
|
|
||||||
on:focus={onFocus}
|
|
||||||
on:hoverItem={(e) => handleHover(e.detail)}
|
|
||||||
on:select={(e) => handleSelect(e.detail.index)}
|
|
||||||
on:blur
|
|
||||||
on:filter={onFilter}>
|
|
||||||
<div class="comfy-select-list" slot="list" let:filteredItems>
|
|
||||||
{#if filteredItems.length > 0}
|
|
||||||
{@const itemSize = isMobile ? 50 : 25}
|
|
||||||
{@const itemsToShow = isMobile ? 10 : 30}
|
|
||||||
<VirtualList
|
|
||||||
items={filteredItems}
|
|
||||||
width="100%"
|
|
||||||
height={Math.min(filteredItems.length, itemsToShow) * itemSize}
|
|
||||||
itemCount={filteredItems.length}
|
|
||||||
{itemSize}
|
|
||||||
overscanCount={5}
|
|
||||||
scrollToIndex={hoverItemIndex}>
|
|
||||||
<div slot="item"
|
|
||||||
class="comfy-select-item"
|
|
||||||
class:mobile={isMobile}
|
|
||||||
let:index={i}
|
|
||||||
let:style
|
|
||||||
{style}
|
|
||||||
class:active={activeIndex === filteredItems[i].index}
|
|
||||||
class:hover={hoverItemIndex === i}
|
|
||||||
on:click={() => handleSelect(filteredItems[i].index)}
|
|
||||||
on:focus={() => handleHover(i)}
|
|
||||||
on:mouseover={() => handleHover(i)}>
|
|
||||||
{@const item = filteredItems[i]}
|
|
||||||
<span class="comfy-select-label">
|
|
||||||
{item.label}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</VirtualList>
|
|
||||||
{:else}
|
|
||||||
<div class="comfy-empty-list">
|
|
||||||
<span>(No items)</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</Select>
|
|
||||||
</label>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
{/if}
|
||||||
{/key}
|
<Select
|
||||||
|
value={$valuesForCombo.length === 0 ? "(Loading...)" : $nodeValue}
|
||||||
|
bind:justValue={option}
|
||||||
|
bind:hoverItemIndex
|
||||||
|
bind:filterText
|
||||||
|
bind:listOpen
|
||||||
|
bind:input
|
||||||
|
items={$valuesForCombo}
|
||||||
|
disabled={$valuesForCombo.length === 0 || isDisabled(widget)}
|
||||||
|
clearable={false}
|
||||||
|
showChevron={true}
|
||||||
|
listAutoWidth={true}
|
||||||
|
inputAttributes={{ autocomplete: 'off' }}
|
||||||
|
on:change
|
||||||
|
on:focus={onFocus}
|
||||||
|
on:hoverItem={(e) => handleHover(e.detail)}
|
||||||
|
on:select={(e) => handleSelect(e.detail.index)}
|
||||||
|
on:blur
|
||||||
|
on:filter={onFilter}>
|
||||||
|
<div class="comfy-select-list" slot="list" let:filteredItems>
|
||||||
|
{#if filteredItems.length > 0}
|
||||||
|
{@const itemSize = isMobile ? 50 : 25}
|
||||||
|
{@const itemsToShow = isMobile ? 10 : 30}
|
||||||
|
<VirtualList
|
||||||
|
items={filteredItems}
|
||||||
|
width="100%"
|
||||||
|
height={Math.min(filteredItems.length, itemsToShow) * itemSize}
|
||||||
|
itemCount={filteredItems.length}
|
||||||
|
{itemSize}
|
||||||
|
overscanCount={5}
|
||||||
|
scrollToIndex={hoverItemIndex}>
|
||||||
|
<div slot="item"
|
||||||
|
class="comfy-select-item"
|
||||||
|
class:mobile={isMobile}
|
||||||
|
let:index={i}
|
||||||
|
let:style
|
||||||
|
{style}
|
||||||
|
class:active={activeIndex === filteredItems[i].index}
|
||||||
|
class:hover={hoverItemIndex === i}
|
||||||
|
on:click={() => handleSelect(filteredItems[i].index)}
|
||||||
|
on:focus={() => handleHover(i)}
|
||||||
|
on:mouseover={() => handleHover(i)}>
|
||||||
|
{@const item = filteredItems[i]}
|
||||||
|
<span class="comfy-select-label">
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</VirtualList>
|
||||||
|
{:else}
|
||||||
|
<div class="comfy-empty-list">
|
||||||
|
<span>(No items)</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</Select>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -257,6 +249,15 @@
|
|||||||
--item-background-hover: var(--comfy-dropdown-item-background-hover);
|
--item-background-hover: var(--comfy-dropdown-item-background-hover);
|
||||||
--item-color-active: var(--comfy-dropdown-item-color-active);
|
--item-color-active: var(--comfy-dropdown-item-color-active);
|
||||||
--item-background-active: var(--comfy-dropdown-item-background-active);
|
--item-background-active: var(--comfy-dropdown-item-background-active);
|
||||||
|
--disabled-color: var(--comfy-disabled-textbox-text-color);
|
||||||
|
--disabled-border-color: var(--comfy-disabled-textbox-border-color);
|
||||||
|
--disabled-background: var(--comfy-disabled-textbox-background-fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:global(.svelte-select.disabled) {
|
||||||
|
--input-color: var(--comfy-disabled-textbox-text-color) !important;
|
||||||
|
--selected-item-color: var(--comfy-disabled-textbox-text-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.svelte-select-list) {
|
:global(.svelte-select-list) {
|
||||||
|
|||||||
308
src/tests/convertA1111ToStdPromptTests.ts
Normal file
308
src/tests/convertA1111ToStdPromptTests.ts
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
import convertA1111ToStdPrompt from "$lib/convertA1111ToStdPrompt";
|
||||||
|
import { expect } from 'vitest';
|
||||||
|
import UnitTest from "./UnitTest";
|
||||||
|
import type { A1111ParsedInfotext } from "$lib/parseA1111";
|
||||||
|
import ComfyBoxStdPrompt from "$lib/ComfyBoxStdPrompt";
|
||||||
|
|
||||||
|
export default class convertA1111ToStdPromptTests extends UnitTest {
|
||||||
|
test__convertsBasic() {
|
||||||
|
const infotext: A1111ParsedInfotext = {
|
||||||
|
positive: "highest quality, masterpiece, best quality, masterpiece, asuka langley sitting cross legged on a chair",
|
||||||
|
negative: "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",
|
||||||
|
height: 512,
|
||||||
|
width: 512,
|
||||||
|
modelHash: "925997e9",
|
||||||
|
cfgScale: 12,
|
||||||
|
sampler: "Euler",
|
||||||
|
seed: 2870305590,
|
||||||
|
steps: 28,
|
||||||
|
extraNetworks: {},
|
||||||
|
extraParams: {
|
||||||
|
"clip skip": "2",
|
||||||
|
"aesthetic embedding": "Belle",
|
||||||
|
"aesthetic lr": "0.0005",
|
||||||
|
"aesthetic slerp": "False",
|
||||||
|
"aesthetic slerp angle": "0.1",
|
||||||
|
"aesthetic steps": "15",
|
||||||
|
"aesthetic text": "",
|
||||||
|
"aesthetic text negative": "False",
|
||||||
|
"aesthetic weight": "0.9",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const converted = convertA1111ToStdPrompt(infotext);
|
||||||
|
|
||||||
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
created_with: "stable-diffusion-webui",
|
||||||
|
extra_data: {}
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
checkpoint: [{
|
||||||
|
model_hashes: {
|
||||||
|
a1111_shorthash: "925997e9",
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
conditioning: [{
|
||||||
|
"$meta": {
|
||||||
|
types: ["positive"]
|
||||||
|
},
|
||||||
|
text: "highest quality, masterpiece, best quality, masterpiece, asuka langley sitting cross legged on a chair",
|
||||||
|
}, {
|
||||||
|
"$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"
|
||||||
|
}],
|
||||||
|
clip: [{
|
||||||
|
clip_skip: 2,
|
||||||
|
}],
|
||||||
|
k_sampler: [{
|
||||||
|
cfg_scale: 12,
|
||||||
|
denoise: 1,
|
||||||
|
sampler_name: "euler",
|
||||||
|
scheduler: "normal",
|
||||||
|
seed: 2870305590,
|
||||||
|
steps: 28
|
||||||
|
}],
|
||||||
|
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.parse(converted)).not.toThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
test__convertsExtraNetworks() {
|
||||||
|
const infotext: A1111ParsedInfotext = {
|
||||||
|
positive: "dreamlike fantasy landscape where everything is a shade of pink,\n dog ",
|
||||||
|
negative: "(worst quality:1.4), (low quality:1.4) , (monochrome:1.1)",
|
||||||
|
width: 640,
|
||||||
|
height: 512,
|
||||||
|
modelHash: "0f0eaaa61e",
|
||||||
|
modelName: "pastelmix-better-vae-fp16",
|
||||||
|
cfgScale: 12,
|
||||||
|
sampler: "DPM++ 2M Karras",
|
||||||
|
seed: 2416682767,
|
||||||
|
steps: 40,
|
||||||
|
denoise: 0.55,
|
||||||
|
extraNetworks: {
|
||||||
|
hypernet: [
|
||||||
|
{ items: ["zxcfc", "0.5", "baz", "quux"], },
|
||||||
|
],
|
||||||
|
lora: [
|
||||||
|
{ items: ["asdfg", "0.8", "foo", "bar"] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
extraParams: {
|
||||||
|
"clip skip": "2",
|
||||||
|
"ensd": "31337",
|
||||||
|
"hires steps": "20",
|
||||||
|
"hires upscale": "2",
|
||||||
|
"hires upscaler": "Latent",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const converted = convertA1111ToStdPrompt(infotext);
|
||||||
|
|
||||||
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
created_with: "stable-diffusion-webui",
|
||||||
|
extra_data: {
|
||||||
|
a1111: {
|
||||||
|
params: {
|
||||||
|
"ensd": "31337"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
checkpoint: [{
|
||||||
|
model_name: "pastelmix-better-vae-fp16",
|
||||||
|
model_hashes: {
|
||||||
|
a1111_shorthash: "0f0eaaa61e",
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
conditioning: [{
|
||||||
|
"$meta": {
|
||||||
|
types: ["positive"]
|
||||||
|
},
|
||||||
|
text: "dreamlike fantasy landscape where everything is a shade of pink,\n dog ",
|
||||||
|
}, {
|
||||||
|
"$meta": {
|
||||||
|
types: ["negative"]
|
||||||
|
},
|
||||||
|
text: "(worst quality:1.4), (low quality:1.4) , (monochrome:1.1)"
|
||||||
|
}],
|
||||||
|
clip: [{
|
||||||
|
clip_skip: 2,
|
||||||
|
}],
|
||||||
|
hypernetwork: [{
|
||||||
|
model_name: "zxcfc",
|
||||||
|
strength: 0.5,
|
||||||
|
}],
|
||||||
|
lora: [{
|
||||||
|
model_name: "asdfg",
|
||||||
|
module_name: "lora",
|
||||||
|
strength_unet: 0.8,
|
||||||
|
strength_tenc: 0.8,
|
||||||
|
}],
|
||||||
|
k_sampler: [{
|
||||||
|
cfg_scale: 12,
|
||||||
|
denoise: 1,
|
||||||
|
sampler_name: "dpmpp_2m",
|
||||||
|
scheduler: "karras",
|
||||||
|
seed: 2416682767,
|
||||||
|
steps: 40
|
||||||
|
}, {
|
||||||
|
"$meta": {
|
||||||
|
types: ["upscale"]
|
||||||
|
},
|
||||||
|
cfg_scale: 12,
|
||||||
|
denoise: 0.55,
|
||||||
|
sampler_name: "dpmpp_2m",
|
||||||
|
scheduler: "karras",
|
||||||
|
seed: 2416682767,
|
||||||
|
steps: 20
|
||||||
|
}],
|
||||||
|
latent_image: [{
|
||||||
|
width: 640,
|
||||||
|
height: 512,
|
||||||
|
}],
|
||||||
|
latent_upscale: [{
|
||||||
|
width: 1280,
|
||||||
|
height: 1024,
|
||||||
|
upscale_by: 2,
|
||||||
|
upscale_method: "Latent"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(() => ComfyBoxStdPrompt.parse(converted)).not.toThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
test__convertsAdditionalNetworks() {
|
||||||
|
const infotext: A1111ParsedInfotext = {
|
||||||
|
positive: "1girl, pink hair",
|
||||||
|
negative: "(worst quality, low quality:1.4)",
|
||||||
|
width: 512,
|
||||||
|
height: 768,
|
||||||
|
modelHash: "0873291ac5",
|
||||||
|
modelName: "AbyssOrangeMix2_nsfw",
|
||||||
|
cfgScale: 6,
|
||||||
|
sampler: "DPM++ SDE Karras",
|
||||||
|
seed: 780207036,
|
||||||
|
steps: 20,
|
||||||
|
denoise: 0.2,
|
||||||
|
extraNetworks: {},
|
||||||
|
extraParams: {
|
||||||
|
"addnet enabled": "True",
|
||||||
|
"addnet model 1": "ElysiaV3-000002(6d3eb064dcc1)",
|
||||||
|
"addnet model 2": "elfmorie2(a34cd9a8c3cc)",
|
||||||
|
"addnet module 1": "LoRA",
|
||||||
|
"addnet module 2": "LoRA",
|
||||||
|
"addnet weight a 1": "0.9",
|
||||||
|
"addnet weight a 2": "1",
|
||||||
|
"addnet weight b 1": "0.7",
|
||||||
|
"addnet weight b 2": "0.8",
|
||||||
|
"ensd": "31337",
|
||||||
|
"mask blur": "1",
|
||||||
|
"sd upscale overlap": "64",
|
||||||
|
"sd upscale upscaler": "4x_Valar_v1",
|
||||||
|
// XXX: just make sure it doesn't fall over for now
|
||||||
|
// this prompt format I swear...
|
||||||
|
"template": "1girl",
|
||||||
|
"negative template": "(worst quality",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const converted = convertA1111ToStdPrompt(infotext)
|
||||||
|
|
||||||
|
expect(converted).toEqual({
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
created_with: "stable-diffusion-webui",
|
||||||
|
extra_data: {
|
||||||
|
a1111: {
|
||||||
|
params: {
|
||||||
|
"ensd": "31337",
|
||||||
|
// TODO
|
||||||
|
"template": "1girl",
|
||||||
|
"negative template": "(worst quality",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
checkpoint: [{
|
||||||
|
model_name: "AbyssOrangeMix2_nsfw",
|
||||||
|
model_hashes: {
|
||||||
|
a1111_shorthash: "0873291ac5",
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
conditioning: [{
|
||||||
|
"$meta": {
|
||||||
|
types: ["positive"]
|
||||||
|
},
|
||||||
|
text: "1girl, pink hair",
|
||||||
|
}, {
|
||||||
|
"$meta": {
|
||||||
|
types: ["negative"]
|
||||||
|
},
|
||||||
|
text: "(worst quality, low quality:1.4)",
|
||||||
|
}],
|
||||||
|
lora: [{
|
||||||
|
module_name: "LoRA",
|
||||||
|
model_name: "ElysiaV3-000002",
|
||||||
|
model_hashes: {
|
||||||
|
addnet_shorthash: "6d3eb064dcc1"
|
||||||
|
},
|
||||||
|
strength_unet: 0.9,
|
||||||
|
strength_tenc: 0.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
module_name: "LoRA",
|
||||||
|
model_name: "elfmorie2",
|
||||||
|
model_hashes: {
|
||||||
|
addnet_shorthash: "a34cd9a8c3cc"
|
||||||
|
},
|
||||||
|
strength_unet: 1,
|
||||||
|
strength_tenc: 0.8,
|
||||||
|
}],
|
||||||
|
k_sampler: [{
|
||||||
|
cfg_scale: 6,
|
||||||
|
denoise: 0.2,
|
||||||
|
sampler_name: "dpmpp_sde",
|
||||||
|
scheduler: "karras",
|
||||||
|
seed: 780207036,
|
||||||
|
steps: 20
|
||||||
|
}],
|
||||||
|
latent_image: [{
|
||||||
|
width: 512,
|
||||||
|
height: 768,
|
||||||
|
mask_blur: 1
|
||||||
|
}],
|
||||||
|
sd_upscale: [{
|
||||||
|
upscaler: "4x_Valar_v1",
|
||||||
|
overlap: 64
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(() => ComfyBoxStdPrompt.parse(converted)).not.toThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
158
src/tests/parseA1111Tests.ts
Normal file
158
src/tests/parseA1111Tests.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import parseA1111 from "$lib/parseA1111";
|
||||||
|
import { expect } from 'vitest';
|
||||||
|
import UnitTest from "./UnitTest";
|
||||||
|
|
||||||
|
export default class parseA1111Tests extends UnitTest {
|
||||||
|
test__parsesBasic() {
|
||||||
|
const infotext = `
|
||||||
|
highest quality, masterpiece, best quality, masterpiece, asuka langley sitting cross legged on a chair
|
||||||
|
Negative prompt: 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
|
||||||
|
Size: 512x512, Seed: 2870305590, Steps: 28, Sampler: Euler, CFG scale: 12, Clip skip: 2, Model hash: 925997e9, Aesthetic LR: 0.0005, Aesthetic text: , Aesthetic slerp: False, Aesthetic steps: 15, Aesthetic weight: 0.9, Aesthetic embedding: Belle, Aesthetic slerp angle: 0.1, Aesthetic text negative: False
|
||||||
|
`
|
||||||
|
|
||||||
|
const parsed = parseA1111(infotext);
|
||||||
|
|
||||||
|
expect(parsed).toEqual({
|
||||||
|
positive: "highest quality, masterpiece, best quality, masterpiece, asuka langley sitting cross legged on a chair",
|
||||||
|
negative: "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",
|
||||||
|
height: 512,
|
||||||
|
width: 512,
|
||||||
|
modelHash: "925997e9",
|
||||||
|
cfgScale: 12,
|
||||||
|
sampler: "Euler",
|
||||||
|
seed: 2870305590,
|
||||||
|
steps: 28,
|
||||||
|
extraNetworks: {},
|
||||||
|
extraParams: {
|
||||||
|
"clip skip": "2",
|
||||||
|
"aesthetic embedding": "Belle",
|
||||||
|
"aesthetic lr": "0.0005",
|
||||||
|
"aesthetic slerp": "False",
|
||||||
|
"aesthetic slerp angle": "0.1",
|
||||||
|
"aesthetic steps": "15",
|
||||||
|
"aesthetic text": "",
|
||||||
|
"aesthetic text negative": "False",
|
||||||
|
"aesthetic weight": "0.9",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test__parsesExtraNetworks() {
|
||||||
|
const infotext = `
|
||||||
|
dreamlike fantasy landscape where everything is a shade of pink,
|
||||||
|
<lora:asdfg:1:foo:bar> dog <hypernet:0.5:baz:quux>
|
||||||
|
Negative prompt: (worst quality:1.4), (low quality:1.4) , (monochrome:1.1)
|
||||||
|
Steps: 40, Sampler: DPM++ 2M Karras, CFG scale: 12, Seed: 2416682767, Size: 640x512, Model hash: 0f0eaaa61e, Model: pastelmix-better-vae-fp16, Denoising strength: 0.55, Clip skip: 2, ENSD: 31337, Hires upscale: 2, Hires steps: 20, Hires upscaler: Latent
|
||||||
|
`
|
||||||
|
const parsed = parseA1111(infotext);
|
||||||
|
|
||||||
|
expect(parsed).toEqual({
|
||||||
|
positive: "dreamlike fantasy landscape where everything is a shade of pink,\n dog ",
|
||||||
|
negative: "(worst quality:1.4), (low quality:1.4) , (monochrome:1.1)",
|
||||||
|
width: 640,
|
||||||
|
height: 512,
|
||||||
|
modelHash: "0f0eaaa61e",
|
||||||
|
modelName: "pastelmix-better-vae-fp16",
|
||||||
|
cfgScale: 12,
|
||||||
|
sampler: "DPM++ 2M Karras",
|
||||||
|
seed: 2416682767,
|
||||||
|
steps: 40,
|
||||||
|
denoise: 0.55,
|
||||||
|
extraNetworks: {
|
||||||
|
hypernet: [
|
||||||
|
{ items: ["0.5", "baz", "quux"], },
|
||||||
|
],
|
||||||
|
lora: [
|
||||||
|
{ items: ["asdfg", "1", "foo", "bar"] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
extraParams: {
|
||||||
|
"clip skip": "2",
|
||||||
|
"ensd": "31337",
|
||||||
|
"hires steps": "20",
|
||||||
|
"hires upscale": "2",
|
||||||
|
"hires upscaler": "Latent",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test__parsesXYZGrid() {
|
||||||
|
const infotext = `
|
||||||
|
1girl
|
||||||
|
Negative prompt: (worst quality, low quality:1.4)
|
||||||
|
Steps: 20, Sampler: DPM++ SDE Karras, CFG scale: 5, Seed: 1964718363, Size: 512x512, Model hash: 736a6f43c2, Denoising strength: 0.5, Clip skip: 2, Hires upscale: 1.75, Hires steps: 14, Hires upscaler: Latent (nearest-exact), Script: X/Y/Z plot, X Type: Prompt S/R, X Values: "<lora:cru5rb:0.5> , <lora:cru5rb:0.6>,<lora:cru5rb:0.7>, <lora:cru5rb:0.8> ,<lora:cru5rb:0.9> , <lora:cru5rb:1>,"
|
||||||
|
`
|
||||||
|
|
||||||
|
const parsed = parseA1111(infotext);
|
||||||
|
|
||||||
|
expect(parsed).toEqual({
|
||||||
|
positive: "1girl",
|
||||||
|
negative: "(worst quality, low quality:1.4)",
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
modelHash: "736a6f43c2",
|
||||||
|
cfgScale: 5,
|
||||||
|
sampler: "DPM++ SDE Karras",
|
||||||
|
seed: 1964718363,
|
||||||
|
steps: 20,
|
||||||
|
denoise: 0.5,
|
||||||
|
extraNetworks: {},
|
||||||
|
extraParams: {
|
||||||
|
"clip skip": "2",
|
||||||
|
"hires steps": "14",
|
||||||
|
"hires upscale": "1.75",
|
||||||
|
"hires upscaler": "Latent (nearest-exact)",
|
||||||
|
"script": "X/Y/Z plot",
|
||||||
|
"x type": "Prompt S/R",
|
||||||
|
"x values": '"<lora:cru5rb:0.5> , <lora:cru5rb:0.6>,<lora:cru5rb:0.7>, <lora:cru5rb:0.8> ,<lora:cru5rb:0.9> , <lora:cru5rb:1>,"',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
test__parsesDynamicPromptsTemplates() {
|
||||||
|
const infotext = `
|
||||||
|
1girl, pink hair
|
||||||
|
Negative prompt: (worst quality, low quality:1.4)
|
||||||
|
Steps: 20, Sampler: DPM++ SDE Karras, CFG scale: 6, Seed: 780207036, Size: 512x768, Model hash: 0873291ac5, Model: AbyssOrangeMix2_nsfw, Denoising strength: 0.2, ENSD: 31337, Mask blur: 1, SD upscale overlap: 64, SD upscale upscaler: 4x_Valar_v1, AddNet Enabled: True, AddNet Module 1: LoRA, AddNet Model 1: ElysiaV3-000002(6d3eb064dcc1), AddNet Weight A 1: 0.9, AddNet Weight B 1: 0.9, AddNet Module 2: LoRA, AddNet Model 2: elfmorie2(a34cd9a8c3cc), AddNet Weight A 2: 1, AddNet Weight B 2: 1
|
||||||
|
Template: 1girl, __haircolor__
|
||||||
|
Negative Template: (worst quality, low quality:1.4), __badprompt__
|
||||||
|
`
|
||||||
|
|
||||||
|
const parsed = parseA1111(infotext);
|
||||||
|
|
||||||
|
expect(parsed).toEqual({
|
||||||
|
positive: "1girl, pink hair",
|
||||||
|
negative: "(worst quality, low quality:1.4)",
|
||||||
|
width: 512,
|
||||||
|
height: 768,
|
||||||
|
modelHash: "0873291ac5",
|
||||||
|
modelName: "AbyssOrangeMix2_nsfw",
|
||||||
|
cfgScale: 6,
|
||||||
|
sampler: "DPM++ SDE Karras",
|
||||||
|
seed: 780207036,
|
||||||
|
steps: 20,
|
||||||
|
denoise: 0.2,
|
||||||
|
extraNetworks: {},
|
||||||
|
extraParams: {
|
||||||
|
"addnet enabled": "True",
|
||||||
|
"addnet model 1": "ElysiaV3-000002(6d3eb064dcc1)",
|
||||||
|
"addnet model 2": "elfmorie2(a34cd9a8c3cc)",
|
||||||
|
"addnet module 1": "LoRA",
|
||||||
|
"addnet module 2": "LoRA",
|
||||||
|
"addnet weight a 1": "0.9",
|
||||||
|
"addnet weight a 2": "1",
|
||||||
|
"addnet weight b 1": "0.9",
|
||||||
|
"addnet weight b 2": "1",
|
||||||
|
"ensd": "31337",
|
||||||
|
"low quality": "1.4)",
|
||||||
|
"mask blur": "1",
|
||||||
|
"sd upscale overlap": "64",
|
||||||
|
"sd upscale upscaler": "4x_Valar_v1",
|
||||||
|
// XXX: just make sure it doesn't fall over for now
|
||||||
|
// this prompt format I swear...
|
||||||
|
"template": "1girl",
|
||||||
|
"negative template": "(worst quality",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
export { default as ComfyPromptSerializerTests } from "./ComfyPromptSerializerTests"
|
export { default as ComfyPromptSerializerTests } from "./ComfyPromptSerializerTests"
|
||||||
export { default as ComfyGraphTests } from "./ComfyGraphTests"
|
export { default as ComfyGraphTests } from "./ComfyGraphTests"
|
||||||
|
export { default as parseA1111Tests } from "./parseA1111Tests"
|
||||||
|
export { default as convertA1111ToStdPromptTests } from "./convertA1111ToStdPromptTests"
|
||||||
|
|||||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
declare const __GIT_COMMIT_HASH__: string
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"checkJs": true,
|
"checkJs": true,
|
||||||
|
"strict": false,
|
||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"paths": {
|
"paths": {
|
||||||
"$lib": ["lib"],
|
"$lib": ["lib"],
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ const isProduction = process.env.NODE_ENV === "production";
|
|||||||
console.log("Production build: " + isProduction)
|
console.log("Production build: " + isProduction)
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
define: {
|
||||||
|
"__GIT_COMMIT_HASH__": '"test"'
|
||||||
|
},
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
base: "./",
|
base: "./",
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
Reference in New Issue
Block a user