Merge branch 'comfyui' into merge_comfy
commit
27f60ea2a7
|
|
@ -11,7 +11,11 @@
|
|||
"Select Lora": "选择 Lora",
|
||||
"use lora in your prompt": "在提示中使用 lora",
|
||||
"Generate": "生成",
|
||||
"Generate txt2img": "生成 txt2img",
|
||||
"Generate Txt2Img": "生成 Txt2Img",
|
||||
"Generate Img2Img": "生成 Img2Img",
|
||||
"Generate Inpaint": "生成 Inpaint",
|
||||
"Generate Outpaint": "生成 Outpaint",
|
||||
"outpaint": "outpaint",
|
||||
"Progress...": "进度...",
|
||||
"Toggle the visibility of the Preview Image on the canvas": "切换画布上预览图像的可见性",
|
||||
"Move and reSize the highlighted layer to fit into the Selection Area": "移动和调整突出显示的图层以适合选择区域",
|
||||
|
|
@ -67,6 +71,7 @@
|
|||
"Random": "随机",
|
||||
"Last": "最后",
|
||||
"Show Samplers": "显示采样器",
|
||||
"Sampling Steps:": "Sampling Steps:",
|
||||
"Select A Script": "选择脚本",
|
||||
"Activate": "激活",
|
||||
"Viewer": "查看器",
|
||||
|
|
@ -181,4 +186,4 @@
|
|||
"Delete all generated images from the canvas": "在画布上删除所有生成图像",
|
||||
"Keep only the highlighted images": "在画布上保留选中的图像",
|
||||
"Generate More": "生成更多"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
41
index.html
41
index.html
|
|
@ -702,6 +702,43 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<!-- searchable menu CSS -->
|
||||
<style>
|
||||
#mySearch {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
background-color: #222;
|
||||
font-weight: bold;
|
||||
}
|
||||
#mySearch:focus {
|
||||
border: 1px solid;
|
||||
border-color: #7a97e4;
|
||||
}
|
||||
#myMenu {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-height: 150px;
|
||||
overflow-y: scroll;
|
||||
background-color: #222;
|
||||
}
|
||||
#myMenu li {
|
||||
color: white;
|
||||
}
|
||||
#myMenu li a {
|
||||
padding: 12px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
#myMenu li a:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<!-- <sp-textarea id="tool_tip" open placement="top">use this when you want to fill empty areas of the canvas</sp-textarea> -->
|
||||
<!-- <sp-tooltip id="tool_tip" open placement="top">use this when you want to fill empty areas of the canvas</sp-tooltip> -->
|
||||
|
|
@ -1142,6 +1179,9 @@
|
|||
<div id="PresetTabContainer"></div>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
<div id="ComfyUIContainer"></div>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1163,6 +1203,7 @@
|
|||
<div class="lexicaContainer"></div>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
<sp-divider class="line-divider" size="large"></sp-divider>
|
||||
<!-- <div id="ComfyUIContainer"></div> -->
|
||||
</div>
|
||||
</uxp-panel>
|
||||
|
||||
|
|
|
|||
18
index.js
18
index.js
|
|
@ -70,6 +70,7 @@ const {
|
|||
logger,
|
||||
toJS,
|
||||
viewer,
|
||||
viewer_util,
|
||||
preview,
|
||||
// session_ts,
|
||||
session_store,
|
||||
|
|
@ -93,6 +94,11 @@ const {
|
|||
stores,
|
||||
lexica,
|
||||
api_ts,
|
||||
comfyui,
|
||||
comfyui_util,
|
||||
comfyui_main_ui,
|
||||
|
||||
comfyapi,
|
||||
} = require('./typescripts/dist/bundle')
|
||||
|
||||
const io = require('./utility/io')
|
||||
|
|
@ -532,8 +538,6 @@ let g_selection = {}
|
|||
let g_b_use_smart_object = true // true to keep layer as smart objects, false to rasterize them
|
||||
let g_sd_options_obj = new sd_options.SdOptions()
|
||||
|
||||
g_sd_options_obj.getOptions()
|
||||
|
||||
let g_controlnet_max_models
|
||||
|
||||
let g_generation_session = new session.GenerationSession(0) //session manager
|
||||
|
|
@ -1795,9 +1799,13 @@ async function openFileFromUrl(url, format = 'gif') {
|
|||
|
||||
// Save the image to a temporary file
|
||||
const tempFolder = await storage.localFileSystem.getTemporaryFolder()
|
||||
const tempFile = await tempFolder.createFile(`temp.${format}`, {
|
||||
overwrite: true,
|
||||
})
|
||||
const randomNumber = Math.floor(Math.random() * 1000000000) // generates a random number between 0 and 999999999
|
||||
const tempFile = await tempFolder.createFile(
|
||||
`temp_${randomNumber}.${format}`,
|
||||
{
|
||||
overwrite: true,
|
||||
}
|
||||
)
|
||||
await tempFile.write(arrayBuffer)
|
||||
|
||||
// Open the file in Photoshop
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "auto.photoshop.stable.diffusion.plugin",
|
||||
"name": "Auto Photoshop Stable Diffusion Plugin",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"host": {
|
||||
"app": "PS",
|
||||
"minVersion": "24.0.0"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "auto-photoshop-stable-diffusion-plugin",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "auto-photoshop-stable-diffusion-plugin",
|
||||
"version": "1.3.3",
|
||||
"version": "1.4.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/photoshop": "^24.5.1",
|
||||
|
|
@ -9272,15 +9272,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undefsafe": {
|
||||
|
|
@ -16652,9 +16652,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz",
|
||||
"integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw=="
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="
|
||||
},
|
||||
"undefsafe": {
|
||||
"version": "2.0.5",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
"@babel/plugin-transform-react-jsx": "^7.21.5",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"babel-loader": "^9.1.2",
|
||||
"chalk": "^5.3.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"commander": "^11.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
|
|
@ -45,7 +46,6 @@
|
|||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.82.1",
|
||||
"webpack-cli": "^5.1.1",
|
||||
"chalk": "^5.3.0",
|
||||
"yazl": "^2.5.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
@ -64,4 +64,4 @@
|
|||
"url": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin#readme"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@
|
|||
"batch_size": 1,
|
||||
"batch_count": 1,
|
||||
"steps": 20,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
|
||||
"ratio": 1,
|
||||
"cfg": 7,
|
||||
"b_width_height_link": true,
|
||||
|
|
@ -28,13 +27,5 @@
|
|||
"hr_upscaler": "",
|
||||
"selection_mode": "ratio"
|
||||
},
|
||||
"controlnet_tab_preset": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
"controlnet_tab_preset": [{}, {}, {}, {}, {}, {}, {}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
"batch_size": 1,
|
||||
"batch_count": 1,
|
||||
"steps": 20,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"ratio": 1,
|
||||
"cfg": 7,
|
||||
"b_width_height_link": true,
|
||||
|
|
@ -28,13 +26,5 @@
|
|||
"hr_upscaler": "",
|
||||
"selection_mode": "ratio"
|
||||
},
|
||||
"controlnet_tab_preset": [
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
"controlnet_tab_preset": [{}, {}, {}, {}, {}, {}, {}]
|
||||
}
|
||||
|
|
|
|||
185
sdapi_py_re.js
185
sdapi_py_re.js
|
|
@ -3,9 +3,6 @@ const { base64ToBase64Url } = require('./utility/general')
|
|||
|
||||
const py_re = require('./utility/sdapi/python_replacement')
|
||||
const Enum = require('./enum')
|
||||
const { control_net } = require('./typescripts/dist/bundle')
|
||||
const { mapPluginSettingsToControlNet, getEnableControlNet, getModuleDetail } =
|
||||
control_net
|
||||
|
||||
const api = require('./utility/api')
|
||||
//javascript plugin can't read images from local directory so we send a request to local server to read the image file and send it back to plugin as image string base64
|
||||
|
|
@ -359,186 +356,6 @@ async function requestExtraSingleImage(payload) {
|
|||
}
|
||||
}
|
||||
|
||||
//REFACTOR: reuse the same code for (requestControlNetTxt2Img,requestControlNetImg2Img)
|
||||
async function requestControlNetTxt2Img(plugin_settings) {
|
||||
console.log('requestControlNetTxt2Img: ')
|
||||
|
||||
// const full_url = `${g_sd_url}/controlnet/txt2img`
|
||||
const full_url = `${g_sd_url}/sdapi/v1/txt2img`
|
||||
|
||||
const control_net_settings = mapPluginSettingsToControlNet(plugin_settings)
|
||||
let control_networks = []
|
||||
// let active_control_networks = 0
|
||||
for (let index = 0; index < g_controlnet_max_models; index++) {
|
||||
if (!getEnableControlNet(index)) {
|
||||
control_networks[index] = false
|
||||
continue
|
||||
}
|
||||
control_networks[index] = true
|
||||
|
||||
if (!control_net_settings['controlnet_units'][index]['input_image']) {
|
||||
app.showAlert('you need to add a valid ControlNet input image')
|
||||
throw 'you need to add a valid ControlNet input image'
|
||||
}
|
||||
|
||||
if (!control_net_settings['controlnet_units'][index]['module']) {
|
||||
app.showAlert('you need to select a valid ControlNet Module')
|
||||
throw 'you need to select a valid ControlNet Module'
|
||||
}
|
||||
|
||||
if (
|
||||
(!control_net_settings['controlnet_units'][index]['model'] &&
|
||||
!getModuleDetail()[
|
||||
control_net_settings['controlnet_units'][index]['module']
|
||||
].model_free) ||
|
||||
control_net_settings['controlnet_units'][index]['model'] === 'none'
|
||||
) {
|
||||
app.showAlert('you need to select a valid ControlNet Model')
|
||||
throw 'you need to select a valid ControlNet Model'
|
||||
}
|
||||
// active_control_networks++
|
||||
}
|
||||
|
||||
let request = await fetch(full_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(control_net_settings),
|
||||
})
|
||||
|
||||
let json = await request.json()
|
||||
console.log('json:', json)
|
||||
|
||||
//update the mask in controlNet tab
|
||||
const numOfImages = json['images'].length
|
||||
let numberOfAnnotations =
|
||||
numOfImages - g_generation_session.last_settings.batch_size
|
||||
if (numberOfAnnotations < 0) numberOfAnnotations = 0
|
||||
|
||||
const base64_mask = json['images'].slice(numOfImages - numberOfAnnotations)
|
||||
|
||||
let mask_index = 0
|
||||
|
||||
for (let index = 0; index < control_networks.length; index++) {
|
||||
if (
|
||||
control_networks[index] == false ||
|
||||
mask_index >= numberOfAnnotations
|
||||
)
|
||||
continue
|
||||
control_net.setControlDetectMapSrc(base64_mask[mask_index], index)
|
||||
g_generation_session.controlNetMask[index] = base64_mask[mask_index]
|
||||
mask_index++
|
||||
}
|
||||
// g_generation_session.controlNetMask = base64_mask
|
||||
|
||||
const standard_response = await py_re.convertToStandardResponse(
|
||||
control_net_settings,
|
||||
json['images'].slice(0, numOfImages - numberOfAnnotations),
|
||||
plugin_settings['uniqueDocumentId']
|
||||
)
|
||||
console.log('standard_response:', standard_response)
|
||||
|
||||
return standard_response
|
||||
}
|
||||
|
||||
//REFACTOR: reuse the same code for (requestControlNetTxt2Img,requestControlNetImg2Img)
|
||||
async function requestControlNetImg2Img(plugin_settings) {
|
||||
console.log('requestControlNetImg2Img: ')
|
||||
|
||||
const full_url = `${g_sd_url}/sdapi/v1/img2img`
|
||||
const control_net_settings = mapPluginSettingsToControlNet(plugin_settings)
|
||||
|
||||
// let control_networks = 0
|
||||
let control_networks = []
|
||||
for (let index = 0; index < g_controlnet_max_models; index++) {
|
||||
if (!getEnableControlNet(index)) {
|
||||
control_networks[index] = false
|
||||
continue
|
||||
}
|
||||
control_networks[index] = true
|
||||
if (!control_net_settings['controlnet_units'][index]['input_image']) {
|
||||
app.showAlert('you need to add a valid ControlNet input image')
|
||||
throw 'you need to add a valid ControlNet input image'
|
||||
}
|
||||
|
||||
if (!control_net_settings['controlnet_units'][index]['module']) {
|
||||
app.showAlert('you need to select a valid ControlNet Module')
|
||||
throw 'you need to select a valid ControlNet Module'
|
||||
}
|
||||
if (
|
||||
(!control_net_settings['controlnet_units'][index]['model'] &&
|
||||
!getModuleDetail()[
|
||||
control_net_settings['controlnet_units'][index]['module']
|
||||
].model_free) ||
|
||||
control_net_settings['controlnet_units'][index]['model'] === 'none'
|
||||
) {
|
||||
app.showAlert('you need to select a valid ControlNet Model')
|
||||
throw 'you need to select a valid ControlNet Model'
|
||||
}
|
||||
}
|
||||
|
||||
let request = await fetch(full_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(control_net_settings),
|
||||
// body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
let json = await request.json()
|
||||
console.log('json:', json)
|
||||
|
||||
//update the mask in controlNet tab
|
||||
const numOfImages = json['images'].length
|
||||
let numberOfAnnotations =
|
||||
numOfImages - g_generation_session.last_settings.batch_size
|
||||
if (numberOfAnnotations < 0) numberOfAnnotations = 0
|
||||
|
||||
// To fix a bug: when Ultimate SD Upscale is active and running, the detection maps won’t be retrieved.
|
||||
// So set its value to 0 to avoid the result images being loaded in the annotation map interface.
|
||||
if (
|
||||
scripts.script_store.isInstalled() &&
|
||||
scripts.script_store.is_active &&
|
||||
scripts.script_store.selected_script_name !== 'None' &&
|
||||
scripts.script_store.is_selected_script_available
|
||||
) {
|
||||
numberOfAnnotations = 0
|
||||
}
|
||||
const base64_mask = json['images'].slice(numOfImages - numberOfAnnotations)
|
||||
|
||||
let mask_index = 0
|
||||
for (let index = 0; index < control_networks.length; index++) {
|
||||
if (
|
||||
control_networks[index] == false ||
|
||||
mask_index >= numberOfAnnotations
|
||||
)
|
||||
continue
|
||||
control_net.setControlDetectMapSrc(base64_mask[mask_index], index)
|
||||
g_generation_session.controlNetMask[index] = base64_mask[mask_index]
|
||||
mask_index++
|
||||
}
|
||||
|
||||
// g_generation_session.controlNetMask = base64_mask
|
||||
|
||||
const standard_response = await py_re.convertToStandardResponse(
|
||||
control_net_settings,
|
||||
json['images'].slice(0, numOfImages - numberOfAnnotations),
|
||||
plugin_settings['uniqueDocumentId']
|
||||
)
|
||||
console.log('standard_response:', standard_response)
|
||||
|
||||
// //get all images except last because it's the mask
|
||||
// for (const image of json['images'].slice(0, -1)) {
|
||||
// await io.IO.base64ToLayer(image)
|
||||
// }
|
||||
|
||||
return standard_response
|
||||
}
|
||||
|
||||
async function isWebuiRunning() {
|
||||
console.log('isWebuiRunning: ')
|
||||
let json = []
|
||||
|
|
@ -577,7 +394,5 @@ module.exports = {
|
|||
// requestHordeStatus,
|
||||
requestExtraSingleImage,
|
||||
|
||||
requestControlNetTxt2Img,
|
||||
requestControlNetImg2Img,
|
||||
isWebuiRunning,
|
||||
}
|
||||
|
|
|
|||
36
selection.js
36
selection.js
|
|
@ -324,6 +324,24 @@ async function channelToSelectionExe(channel_name = 'mask') {
|
|||
}
|
||||
}
|
||||
|
||||
function keepRatio(selectionInfo, offset) {
|
||||
// Calculate the current width and height
|
||||
let width = selectionInfo.right - selectionInfo.left
|
||||
let height = selectionInfo.bottom - selectionInfo.top
|
||||
|
||||
// Calculate the new coordinates with the offset
|
||||
selectionInfo.right += offset
|
||||
selectionInfo.left -= offset
|
||||
selectionInfo.bottom += offset
|
||||
selectionInfo.top -= offset
|
||||
|
||||
// Update width and height
|
||||
selectionInfo.width = width + 2 * offset
|
||||
selectionInfo.height = height + 2 * offset
|
||||
|
||||
return selectionInfo
|
||||
}
|
||||
|
||||
function makeSquare(selectionInfo, offset) {
|
||||
// Calculate the current width and height
|
||||
let width = selectionInfo.right - selectionInfo.left
|
||||
|
|
@ -349,12 +367,20 @@ function makeSquare(selectionInfo, offset) {
|
|||
return selectionInfo
|
||||
}
|
||||
|
||||
async function inpaintLassoInitImageAndMask(channel_name = 'mask', offset = 0) {
|
||||
async function inpaintLassoInitImageAndMask(
|
||||
channel_name = 'mask',
|
||||
offset = 0,
|
||||
make_square = true
|
||||
) {
|
||||
const selectionInfo = await psapi.getSelectionInfoExe()
|
||||
//convert the selection box into square box so that you have best output results
|
||||
const squareSelection = makeSquare(selectionInfo, offset)
|
||||
|
||||
const newSelection = make_square
|
||||
? makeSquare(selectionInfo, offset)
|
||||
: keepRatio(selectionInfo, offset)
|
||||
|
||||
//correct width and height sliders, since this is lasso mode.
|
||||
await calcWidthHeightFromSelection(squareSelection)
|
||||
await calcWidthHeightFromSelection(newSelection)
|
||||
|
||||
async function getImageFromCanvas() {
|
||||
const width = html_manip.getWidth()
|
||||
|
|
@ -363,7 +389,7 @@ async function inpaintLassoInitImageAndMask(channel_name = 'mask', offset = 0) {
|
|||
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
||||
width,
|
||||
height,
|
||||
squareSelection,
|
||||
newSelection,
|
||||
true
|
||||
)
|
||||
return base64
|
||||
|
|
@ -396,7 +422,7 @@ async function inpaintLassoInitImageAndMask(channel_name = 'mask', offset = 0) {
|
|||
synchronousExecution: true,
|
||||
})
|
||||
// const selection_info = await psapi.getSelectionInfoExe()
|
||||
mask_base64 = await fillSelectionWhiteOutsideBlack(squareSelection)
|
||||
mask_base64 = await fillSelectionWhiteOutsideBlack(newSelection)
|
||||
})
|
||||
|
||||
//save laso selection to channel
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { ErrorBoundary } from '../util/errorBoundary'
|
|||
import { ScriptMode } from '../util/ts/enum'
|
||||
|
||||
import './style/after_detailer.css'
|
||||
import Locale from '../locale/locale'
|
||||
|
||||
declare let g_sd_url: string
|
||||
|
||||
|
|
@ -133,8 +134,7 @@ export class AfterDetailerComponent extends React.Component<{
|
|||
Automatic1111 webui
|
||||
</sp-label>
|
||||
<button
|
||||
className="btnSquare refreshButton"
|
||||
id="btnResetSettings"
|
||||
className="btnSquare refreshButton btnResetSettings"
|
||||
title="Refresh the ADetailer Extension"
|
||||
onClick={this.handleRefresh}
|
||||
></button>
|
||||
|
|
@ -150,12 +150,11 @@ export class AfterDetailerComponent extends React.Component<{
|
|||
store.updateProperty('is_enabled', event.target.checked)
|
||||
}}
|
||||
>
|
||||
{'Activate'}
|
||||
{Locale('Activate')}
|
||||
</sp-checkbox>
|
||||
<SpMenu
|
||||
title="model"
|
||||
items={store.data.model_list}
|
||||
// disabled={script_store.disabled}
|
||||
// style="width: 199px; margin-right: 5px"
|
||||
label_item="Select a ADetailer Model"
|
||||
// id={'model_list'}
|
||||
|
|
@ -219,7 +218,6 @@ export class AfterDetailerComponent extends React.Component<{
|
|||
<SpMenu
|
||||
title="controlnet inpaint model"
|
||||
items={store.data.controlnet_models}
|
||||
// disabled={script_store.disabled}
|
||||
// style="width: 199px; margin-right: 5px"
|
||||
label_item="Select a ControlNet Model"
|
||||
// id={'model_list'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
import { app } from 'photoshop'
|
||||
import settings_tab from '../settings/settings'
|
||||
import { requestGet, requestPost } from '../util/ts/api'
|
||||
import { base64UrlToBase64 } from '../util/ts/general'
|
||||
interface ComfyError {
|
||||
type: string
|
||||
message: string
|
||||
details: string
|
||||
extra_info: any
|
||||
}
|
||||
|
||||
interface NodeError {
|
||||
errors: ComfyError[]
|
||||
dependent_outputs: string[]
|
||||
class_type: string
|
||||
}
|
||||
export interface ComfyResult {
|
||||
error?: ComfyError
|
||||
node_errors?: { [key: string]: NodeError }
|
||||
}
|
||||
class ComfyAPI {
|
||||
private object_info: Record<string, any> = {}
|
||||
comfy_url: string
|
||||
status: boolean = false
|
||||
|
||||
constructor(comfy_url: string) {
|
||||
this.comfy_url = comfy_url
|
||||
}
|
||||
async init() {
|
||||
try {
|
||||
this.object_info = await this.initializeObjectInfo(this.comfy_url)
|
||||
this.status = true
|
||||
return this.object_info
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
app.showAlert(`${e}`)
|
||||
this.status = false
|
||||
}
|
||||
}
|
||||
setUrl(comfy_url: string) {
|
||||
this.comfy_url = comfy_url
|
||||
}
|
||||
async refresh() {
|
||||
this.object_info = await this.initializeObjectInfo(this.comfy_url)
|
||||
}
|
||||
async queue() {
|
||||
const res = await requestGet(`${this.comfy_url}/queue`)
|
||||
const queue_running = res?.queue_running ? res?.queue_running : []
|
||||
const queue_pending = res?.queue_pending ? res?.queue_pending : []
|
||||
return { queue_running, queue_pending }
|
||||
}
|
||||
async prompt(prompt: any) {
|
||||
try {
|
||||
const payload = {
|
||||
prompt: prompt,
|
||||
}
|
||||
const res = await requestPost(`${this.comfy_url}/prompt`, payload)
|
||||
|
||||
return res
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async getHistory(prompt_id: string = '') {
|
||||
try {
|
||||
const url = `http://127.0.0.1:8188/history/${prompt_id}`
|
||||
const res = await requestGet(`${this.comfy_url}/history`)
|
||||
return res
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
async view(
|
||||
filename: string,
|
||||
type: string = 'output',
|
||||
subfolder: string = ''
|
||||
): Promise<string> {
|
||||
const ab: ArrayBuffer = await requestGet(
|
||||
`${this.comfy_url}/view?subfolder=${subfolder}&type=${type}&filename=${filename}`
|
||||
)
|
||||
return Buffer.from(ab).toString('base64')
|
||||
}
|
||||
|
||||
async initializeObjectInfo(comfy_url: string) {
|
||||
try {
|
||||
const full_url = `${comfy_url}/object_info`
|
||||
const object_info = await requestGet(full_url)
|
||||
if (!object_info)
|
||||
throw `can not request from comfyui url: ${comfy_url}`
|
||||
return object_info
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
getObjectInfo() {
|
||||
try {
|
||||
return this.object_info
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
getReadableError(result: ComfyResult): string {
|
||||
const parseError = (error: any) =>
|
||||
`Error: ${error.message}\n${
|
||||
error.details ? `Details: ${error.details}\n` : ''
|
||||
}`
|
||||
|
||||
let errorMessage = result.error ? parseError(result.error) : ''
|
||||
|
||||
if (result.node_errors) {
|
||||
for (const [node_id, node_error] of Object.entries(
|
||||
result.node_errors
|
||||
)) {
|
||||
errorMessage += `Node ${node_id}:\n${node_error.errors
|
||||
.map(parseError)
|
||||
.join('')}`
|
||||
}
|
||||
}
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
private getData(path: string[]): any[] {
|
||||
let data = []
|
||||
try {
|
||||
let obj = this.object_info
|
||||
for (const p of path) {
|
||||
obj = obj[p]
|
||||
}
|
||||
data = obj[0]
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to get data from path ${path.join('.')}: ${e}`
|
||||
)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
getModels(): any[] {
|
||||
return this.getData([
|
||||
'CheckpointLoader',
|
||||
'input',
|
||||
'required',
|
||||
'ckpt_name',
|
||||
])
|
||||
}
|
||||
|
||||
getVAEs(): any[] {
|
||||
return this.getData(['VAELoader', 'input', 'required', 'vae_name'])
|
||||
}
|
||||
getSamplerNames(): string[] {
|
||||
return this.getData(['KSampler', 'input', 'required', 'sampler_name'])
|
||||
}
|
||||
getHiResUpscalers(): string[] {
|
||||
return this.getData([
|
||||
'LatentUpscaleBy',
|
||||
'input',
|
||||
'required',
|
||||
'upscale_method',
|
||||
])
|
||||
}
|
||||
getLoras(): string[] {
|
||||
return this.getData(['LoraLoader', 'input', 'required', 'lora_name'])
|
||||
}
|
||||
async interrupt() {
|
||||
const res = await requestPost(`${this.comfy_url}/interrupt`, {})
|
||||
console.log('res: ', res)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
ComfyAPI,
|
||||
comfy_api: new ComfyAPI(settings_tab.store.data.comfy_url),
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,299 @@
|
|||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 532429388244110,
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "dpmpp_sde",
|
||||
"scheduler": "karras",
|
||||
"denoise": 0.72,
|
||||
"model": [
|
||||
"76",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"91",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"91",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"63",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"76",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"76",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"78",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"78",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"seed": 4820153955672,
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "dpmpp_2m",
|
||||
"scheduler": "simple",
|
||||
"denoise": 0.4,
|
||||
"model": [
|
||||
"76",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"91",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"91",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"55",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"13",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"11",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"55": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"scale_by": 2,
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LatentUpscaleBy"
|
||||
},
|
||||
"57": {
|
||||
"inputs": {
|
||||
"vae_name": "MoistMix.vae.pt"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"58": {
|
||||
"inputs": {
|
||||
"image": "Layer 3 (1).png",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"59": {
|
||||
"inputs": {
|
||||
"pixels": [
|
||||
"60",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEEncode"
|
||||
},
|
||||
"60": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"crop": "disabled",
|
||||
"image": [
|
||||
"58",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImageScale"
|
||||
},
|
||||
"63": {
|
||||
"inputs": {
|
||||
"amount": 1,
|
||||
"samples": [
|
||||
"59",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "RepeatLatentBatch"
|
||||
},
|
||||
"76": {
|
||||
"inputs": {
|
||||
"prompt": "",
|
||||
"model": [
|
||||
"78",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"109",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"78": {
|
||||
"inputs": {
|
||||
"prompt": "bad hands, text, watermark",
|
||||
"model": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"109",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"88": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"91",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"89": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"91",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"90": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"91",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"91": {
|
||||
"inputs": {
|
||||
"is_enabled_1": "disable",
|
||||
"preprocessor_name_1": "CannyEdgePreprocessor",
|
||||
"control_net_name_1": "control_lora_rank128_v11p_sd15_canny_fp16.safetensors",
|
||||
"strength_1": 1,
|
||||
"threshold_a_1": 100,
|
||||
"threshold_b_1": 200,
|
||||
"start_percent_1": 0,
|
||||
"end_percent_1": 1,
|
||||
"resolution_1": 512,
|
||||
"is_enabled_2": "disable",
|
||||
"preprocessor_name_2": "OpenposePreprocessor",
|
||||
"control_net_name_2": "control_lora_rank128_v11p_sd15_openpose_fp16.safetensors",
|
||||
"strength_2": 1,
|
||||
"threshold_a_2": 0,
|
||||
"threshold_b_2": 0,
|
||||
"start_percent_2": 0,
|
||||
"end_percent_2": 1,
|
||||
"resolution_2": 512,
|
||||
"is_enabled_3": "disable",
|
||||
"preprocessor_name_3": "InpaintPreprocessor",
|
||||
"control_net_name_3": "control_lora_rank128_v11p_sd15_inpaint_fp16.safetensors",
|
||||
"strength_3": 1,
|
||||
"threshold_a_3": 0,
|
||||
"threshold_b_3": 0,
|
||||
"start_percent_3": 0,
|
||||
"end_percent_3": 1,
|
||||
"resolution_3": 512,
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetScript"
|
||||
},
|
||||
"109": {
|
||||
"inputs": {
|
||||
"stop_at_clip_layer": -1,
|
||||
"clip": [
|
||||
"16",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPSetLastLayer"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,345 @@
|
|||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": [
|
||||
"141",
|
||||
0
|
||||
],
|
||||
"steps": 20,
|
||||
"cfg": 7,
|
||||
"sampler_name": "euler_ancestral",
|
||||
"scheduler": "karras",
|
||||
"denoise": 0.71,
|
||||
"model": [
|
||||
"76",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"159",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"159",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"160",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"76",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"76",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"78",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"78",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"seed": 4820153955672,
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "dpmpp_2m",
|
||||
"scheduler": "simple",
|
||||
"denoise": 0.4,
|
||||
"model": [
|
||||
"76",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"159",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"159",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"55",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"13",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"11",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"ckpt_name": "aniverse_v15Pruned.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"55": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"scale_by": 2,
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LatentUpscaleBy"
|
||||
},
|
||||
"57": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"58": {
|
||||
"inputs": {
|
||||
"image": "04b380cb676f37e52d5963a0982edd5e.jpg",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"76": {
|
||||
"inputs": {
|
||||
"prompt": "young teen:1.2, (cute girl:1.2)",
|
||||
"model": [
|
||||
"78",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"162",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"78": {
|
||||
"inputs": {
|
||||
"prompt": "bad hands, text, watermark",
|
||||
"model": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"162",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"83": {
|
||||
"inputs": {
|
||||
"image": "pasted/image (4).png",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"135": {
|
||||
"inputs": {
|
||||
"content_mask": "original",
|
||||
"width": 512,
|
||||
"height": 768,
|
||||
"seed": [
|
||||
"141",
|
||||
0
|
||||
],
|
||||
"init_image": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"mask": [
|
||||
"83",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ContentMaskLatent"
|
||||
},
|
||||
"141": {
|
||||
"inputs": {
|
||||
"seed": 519416762507340
|
||||
},
|
||||
"class_type": "APS_Seed"
|
||||
},
|
||||
"155": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 768,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"156": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"159",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"157": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"159",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"158": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"159",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"159": {
|
||||
"inputs": {
|
||||
"is_enabled_1": "disable",
|
||||
"preprocessor_name_1": "OpenposePreprocessor",
|
||||
"control_net_name_1": "control_lora_rank128_v11p_sd15_openpose_fp16.safetensors",
|
||||
"strength_1": 1,
|
||||
"threshold_a_1": 100,
|
||||
"threshold_b_1": 200,
|
||||
"start_percent_1": 0,
|
||||
"end_percent_1": 1,
|
||||
"resolution_1": 512,
|
||||
"is_enabled_2": "disable",
|
||||
"preprocessor_name_2": "OpenposePreprocessor",
|
||||
"control_net_name_2": "control_lora_rank128_v11p_sd15_openpose_fp16.safetensors",
|
||||
"strength_2": 1,
|
||||
"threshold_a_2": 0,
|
||||
"threshold_b_2": 0,
|
||||
"start_percent_2": 0,
|
||||
"end_percent_2": 1,
|
||||
"resolution_2": 512,
|
||||
"is_enabled_3": "enable",
|
||||
"preprocessor_name_3": "InpaintPreprocessor",
|
||||
"control_net_name_3": "control_lora_rank128_v11p_sd15_inpaint_fp16.safetensors",
|
||||
"strength_3": 1,
|
||||
"threshold_a_3": 0,
|
||||
"threshold_b_3": 0,
|
||||
"start_percent_3": 0,
|
||||
"end_percent_3": 1,
|
||||
"resolution_3": 512,
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"image_1": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"mask_1": [
|
||||
"83",
|
||||
0
|
||||
],
|
||||
"image_2": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"mask_2": [
|
||||
"83",
|
||||
0
|
||||
],
|
||||
"image_3": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"mask_3": [
|
||||
"83",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetScript"
|
||||
},
|
||||
"160": {
|
||||
"inputs": {
|
||||
"amount": 1,
|
||||
"samples": [
|
||||
"135",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "RepeatLatentBatch"
|
||||
},
|
||||
"162": {
|
||||
"inputs": {
|
||||
"stop_at_clip_layer": -1,
|
||||
"clip": [
|
||||
"16",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPSetLastLayer"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,570 @@
|
|||
import txt2img from './txt2img_workflow.json'
|
||||
import txt2img_api from './txt2img_api.json'
|
||||
|
||||
import img2img from './img2img_workflow.json'
|
||||
import img2img_api from './img2img_api.json'
|
||||
|
||||
import inpaint from './inpaint_workflow.json'
|
||||
import inpaint_api from './inpaint_api.json'
|
||||
|
||||
import vae_settings from '../settings/vae'
|
||||
import sd_tab_util from '../sd_tab/util'
|
||||
import comfyui_util from './util'
|
||||
import util from './util'
|
||||
import { store } from './util'
|
||||
|
||||
import { base64UrlToBase64, copyJson } from '../util/ts/general'
|
||||
import { session_store } from '../stores'
|
||||
import ControlNetStore from '../controlnet/store'
|
||||
import { setControlDetectMapSrc } from '../controlnet/entry'
|
||||
|
||||
// Function to parse metadata from a title string
|
||||
function parseMetadata(title: string) {
|
||||
if (!title) return {}
|
||||
// Split the title into parts using the "|" character and trim whitespace from each part
|
||||
|
||||
var parts = title.split('|').map((part) => part.trim())
|
||||
// Take the last part as the metadata
|
||||
var metadataPart = parts[parts.length - 1]
|
||||
// Initialize an empty object to store the key-value pairs
|
||||
var result: Record<string, string> = {}
|
||||
// If there is more than one part, there is metadata to parse
|
||||
if (parts.length > 1) {
|
||||
// Split the metadata into pairs using the "," character and trim whitespace from each pair
|
||||
var pairs = metadataPart.split(',').map((pair) => pair.trim())
|
||||
|
||||
// For each pair...
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
// If the pair includes a ":" character, it is a key-value pair
|
||||
if (pairs[i].includes(':')) {
|
||||
// Split the pair into a key and a value using the ":" character and trim whitespace
|
||||
var pair = pairs[i].split(':').map((part) => part.trim())
|
||||
|
||||
// Add the key-value pair to the result object
|
||||
result[pair[0]] = pair[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result object containing the key-value pairs
|
||||
return result
|
||||
}
|
||||
|
||||
function getInput(node: any, name: string) {
|
||||
const input = node.inputs.filter((input: any) => {
|
||||
return input?.widget?.name === name
|
||||
})?.[0]
|
||||
return input
|
||||
}
|
||||
function getNode(nodes: any[], node_id: string) {
|
||||
const node = nodes.filter((node: any) => {
|
||||
return parseInt(node.id) === parseInt(node_id)
|
||||
})?.[0]
|
||||
return node
|
||||
}
|
||||
function getNodeByNameId(nodes: any[], node_name_id: string) {
|
||||
const node = nodes.filter((node: any) => {
|
||||
const node_metadata = parseMetadata(node.title)
|
||||
return node_metadata.id === node_name_id
|
||||
})?.[0]
|
||||
return node
|
||||
}
|
||||
|
||||
function getPromptNodeByNameId(
|
||||
nodes: any[], //nodes from workflow.json
|
||||
prompt: any, //prompt from api.json
|
||||
node_name_id: string // name_id I'm using to get access to nodes by their name
|
||||
) {
|
||||
const node = getNodeByNameId(nodes, node_name_id)
|
||||
const prompt_node = node?.id ? prompt[node.id] : {}
|
||||
|
||||
return prompt_node
|
||||
}
|
||||
function setInputValue(
|
||||
nodes: any[],
|
||||
prompt: any,
|
||||
node_name_id: string,
|
||||
input_name: string,
|
||||
new_value: any
|
||||
) {
|
||||
try {
|
||||
var prompt_node = getPromptNodeByNameId(nodes, prompt, node_name_id)
|
||||
prompt_node.inputs[input_name] = new_value
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Node Name ID:\n${node_name_id}\n` +
|
||||
`Input Name:\n${input_name}\n` +
|
||||
`New Value:\n${new_value}\n` +
|
||||
`Prompt Node:\n${prompt_node}\n` +
|
||||
`Error:\n${e}`
|
||||
)
|
||||
}
|
||||
}
|
||||
function getLink(links: any[], link_id: number) {
|
||||
return links.filter((link: any) => {
|
||||
return link[0] === link_id
|
||||
})?.[0]
|
||||
}
|
||||
|
||||
function getNodesFromLink(link: any) {
|
||||
return {
|
||||
from_node: { id: link[1], input_index: link[2] },
|
||||
to_node: { id: link[3], input_index: link[4] },
|
||||
}
|
||||
}
|
||||
function mutePromptNode(nodes: any[], prompt: any, node_name_id: string) {
|
||||
const node = getNodeByNameId(nodes, node_name_id)
|
||||
delete prompt[node.id]
|
||||
return prompt
|
||||
}
|
||||
const txt2img_map: Record<string, any> = {
|
||||
model: 'checkpoint.ckpt_name',
|
||||
comfy_clip_skip: 'clip_skip.stop_at_clip_layer',
|
||||
vae: 'vae.vae_name',
|
||||
width: 'latent_image.width',
|
||||
height: 'latent_image.height',
|
||||
batch_size: 'latent_image.batch_size',
|
||||
prompt: 'multi_loras_positive_prompt.prompt',
|
||||
negative_prompt: 'multi_loras_negative_prompt.prompt',
|
||||
|
||||
//sampler node
|
||||
|
||||
seed: 'sampler.seed',
|
||||
steps: 'sampler.steps',
|
||||
cfg_scale: 'sampler.cfg',
|
||||
sampler_index: 'sampler.sampler_name',
|
||||
// scheduler: 'normal',
|
||||
// denoising_strength: 'sampler.denoise', // keep it at default value 1.0
|
||||
|
||||
//hires_node node:
|
||||
hr_scale: 'scaler.scale_by',
|
||||
upscale_method: 'nearest_exact',
|
||||
|
||||
hr_seed: 'hires_sampler.seed',
|
||||
hr_second_pass_steps: 'hires_sampler.steps',
|
||||
// hr_cfg: 'hires_sampler.cfg', // keep at default value 0.5
|
||||
// hr_sampler_name: 'hires_sampler.sampler_name',
|
||||
// hr_scheduler: 'normal',
|
||||
hr_denoising_strength: 'hires_sampler.denoise',
|
||||
}
|
||||
const controlnet_txt2img_map: Record<string, any> = {
|
||||
comfy_input_image: 'controlnet_script.image', //map controlnet_units[unit_index].input_image from base64 string to comfy image filename
|
||||
comfy_mask: 'controlnet_script.mask', //map controlnet_units[unit_index].mask from base64 string to comfy image filename
|
||||
comfy_enabled: 'controlnet_script.is_enabled', //map controlnet_units[unit_index].enabled from boolean [true,false] to ['enable', 'disable']
|
||||
module: 'controlnet_script.preprocessor_name',
|
||||
model: 'controlnet_script.control_net_name',
|
||||
weight: 'controlnet_script.strength',
|
||||
guidance_start: 'controlnet_script.start_percent',
|
||||
guidance_end: 'controlnet_script.end_percent',
|
||||
processor_res: 'controlnet_script.resolution',
|
||||
threshold_a: 'controlnet_script.threshold_a',
|
||||
threshold_b: 'controlnet_script.threshold_b',
|
||||
}
|
||||
const img2img_map: Record<string, any> = {
|
||||
init_image: 'init_image.image', // note: this is not init_images but init_image
|
||||
model: 'checkpoint.ckpt_name',
|
||||
comfy_clip_skip: 'clip_skip.stop_at_clip_layer',
|
||||
vae: 'vae.vae_name',
|
||||
width: 'init_image_scale.width',
|
||||
height: 'init_image_scale.height',
|
||||
batch_size: 'latent_batch.amount',
|
||||
// prompt: 'positive_prompt.text',
|
||||
prompt: 'multi_loras_positive_prompt.prompt',
|
||||
negative_prompt: 'multi_loras_negative_prompt.prompt',
|
||||
|
||||
//sampler node
|
||||
|
||||
seed: 'sampler.seed',
|
||||
steps: 'sampler.steps',
|
||||
cfg_scale: 'sampler.cfg',
|
||||
sampler_index: 'sampler.sampler_name',
|
||||
// scheduler: 'normal',
|
||||
denoising_strength: 'sampler.denoise',
|
||||
|
||||
//hires_node node:
|
||||
hr_scale: 'scaler.scale_by',
|
||||
upscale_method: 'nearest_exact',
|
||||
|
||||
hr_seed: 'hires_sampler.seed',
|
||||
hr_second_pass_steps: 'hires_sampler.steps',
|
||||
// hr_cfg: 'hires_sampler.cfg', // keep at default value 0.5
|
||||
// hr_sampler_name: 'hires_sampler.sampler_name',
|
||||
// hr_scheduler: 'normal',
|
||||
hr_denoising_strength: 'hires_sampler.denoise',
|
||||
}
|
||||
const inpaint_map: Record<string, any> = {
|
||||
init_image: 'init_image.image', // note: this is not init_images but init_image
|
||||
comfy_mask: 'mask_image.image',
|
||||
model: 'checkpoint.ckpt_name',
|
||||
comfy_clip_skip: 'clip_skip.stop_at_clip_layer',
|
||||
vae: 'vae.vae_name',
|
||||
width: 'content_mask_latent.width',
|
||||
height: 'content_mask_latent.height',
|
||||
batch_size: 'latent_batch.amount',
|
||||
// prompt: 'positive_prompt.text',
|
||||
prompt: 'multi_loras_positive_prompt.prompt',
|
||||
negative_prompt: 'multi_loras_negative_prompt.prompt',
|
||||
|
||||
comfy_content_mask: 'content_mask_latent.content_mask',
|
||||
|
||||
//sampler node
|
||||
|
||||
seed: 'first_pass_seed.seed',
|
||||
steps: 'sampler.steps',
|
||||
cfg_scale: 'sampler.cfg',
|
||||
sampler_index: 'sampler.sampler_name',
|
||||
// scheduler: 'normal',
|
||||
denoising_strength: 'sampler.denoise',
|
||||
|
||||
//hires_node node:
|
||||
hr_scale: 'scaler.scale_by',
|
||||
upscale_method: 'nearest_exact',
|
||||
|
||||
hr_seed: 'hires_sampler.seed',
|
||||
hr_second_pass_steps: 'hires_sampler.steps',
|
||||
// hr_cfg: 'hires_sampler.cfg', // keep at default value 0.5
|
||||
// hr_sampler_name: 'hires_sampler.sampler_name',
|
||||
// hr_scheduler: 'normal',
|
||||
hr_denoising_strength: 'hires_sampler.denoise',
|
||||
}
|
||||
async function reuseOrUploadComfyImage(
|
||||
base64: string,
|
||||
all_uploaded_images: Record<string, any>
|
||||
) {
|
||||
let image_name: string = ''
|
||||
if (all_uploaded_images[base64]) {
|
||||
image_name = all_uploaded_images[base64]
|
||||
} else {
|
||||
const new_loaded_image = await util.uploadImage(false, base64)
|
||||
console.log('new_loaded_image: ', new_loaded_image)
|
||||
if (new_loaded_image) {
|
||||
store.data.uploaded_images_list = [
|
||||
...store.data.uploaded_images_list,
|
||||
new_loaded_image.name,
|
||||
]
|
||||
image_name = new_loaded_image.name
|
||||
all_uploaded_images[base64] = new_loaded_image.name
|
||||
}
|
||||
}
|
||||
return image_name
|
||||
}
|
||||
async function addMissingSettings(plugin_settings: Record<string, any>) {
|
||||
plugin_settings['vae'] = vae_settings.store.data.current_vae
|
||||
plugin_settings['model'] = sd_tab_util.store.data.selected_model
|
||||
plugin_settings['hr_denoising_strength'] =
|
||||
sd_tab_util.store.data.hr_denoising_strength
|
||||
plugin_settings['hr_sampler_name'] = sd_tab_util.store.data.sampler_name // use the same sampler for the first and second pass (hires) upscale sampling steps
|
||||
plugin_settings['comfy_clip_skip'] = -1 * plugin_settings['clip_skip']
|
||||
if ('init_images' in plugin_settings) {
|
||||
const base64 = plugin_settings['init_images'][0]
|
||||
|
||||
plugin_settings['init_image'] = await reuseOrUploadComfyImage(
|
||||
base64,
|
||||
store.data.base64_to_uploaded_images_names
|
||||
)
|
||||
}
|
||||
if ('mask' in plugin_settings) {
|
||||
const base64 = plugin_settings['mask']
|
||||
|
||||
plugin_settings['comfy_mask'] = await reuseOrUploadComfyImage(
|
||||
base64,
|
||||
store.data.base64_to_uploaded_images_names
|
||||
)
|
||||
}
|
||||
|
||||
//calculate positive random seed if seed is -1
|
||||
const random_seed: bigint = util.getRandomBigIntApprox(
|
||||
0n,
|
||||
18446744073709552000n
|
||||
)
|
||||
|
||||
plugin_settings['seed'] =
|
||||
parseInt(plugin_settings['seed']) === -1
|
||||
? random_seed.toString()
|
||||
: plugin_settings['seed'] // use the same as the main seed
|
||||
|
||||
session_store.data.last_seed = plugin_settings['seed']
|
||||
plugin_settings['hr_seed'] = plugin_settings['seed']
|
||||
|
||||
return plugin_settings
|
||||
}
|
||||
|
||||
async function addMissingControlnetSettings(
|
||||
plugin_settings: Record<string, any>
|
||||
) {
|
||||
plugin_settings['disableControlNetTab'] =
|
||||
ControlNetStore.disableControlNetTab
|
||||
for (const unit of plugin_settings['controlnet_units']) {
|
||||
unit['comfy_enabled'] =
|
||||
!plugin_settings['disableControlNetTab'] && unit.enabled
|
||||
? 'enable'
|
||||
: 'disable'
|
||||
|
||||
unit['comfy_input_image'] = ''
|
||||
unit['comfy_mask'] = ''
|
||||
if ('input_image' in unit && unit['input_image'] !== '') {
|
||||
const base64 = unit['input_image']
|
||||
unit['comfy_input_image'] = await reuseOrUploadComfyImage(
|
||||
base64,
|
||||
store.data.base64_to_uploaded_images_names
|
||||
)
|
||||
}
|
||||
if ('mask' in unit && unit['mask'] !== '') {
|
||||
//if mask have been set manually
|
||||
const base64 = unit['mask']
|
||||
|
||||
unit['comfy_mask'] = await reuseOrUploadComfyImage(
|
||||
base64,
|
||||
store.data.base64_to_uploaded_images_names
|
||||
)
|
||||
} else if ('comfy_mask' in plugin_settings) {
|
||||
// use the mask from the main ui (inpaint and outpaint mode)
|
||||
|
||||
unit['comfy_mask'] = plugin_settings['comfy_mask']
|
||||
}
|
||||
|
||||
//set model and module to 'None' if no item has been selection, so comfyui won't through an error
|
||||
unit['model'] =
|
||||
unit['model'] === '' || unit['comfy_enabled'] === 'disable'
|
||||
? 'None'
|
||||
: unit['model']
|
||||
unit['module'] =
|
||||
unit['module'] === '' || unit['comfy_enabled'] === 'disable'
|
||||
? 'None'
|
||||
: unit['module']
|
||||
}
|
||||
return plugin_settings
|
||||
}
|
||||
async function mapPluginSettingsToComfyuiPrompt(
|
||||
nodes: any[],
|
||||
prompt: any,
|
||||
plugin_settings: any,
|
||||
mode_map: any
|
||||
) {
|
||||
try {
|
||||
// const plugin_param = 'steps'
|
||||
plugin_settings = await addMissingSettings(plugin_settings)
|
||||
function mapPluginInputToComfyInput(
|
||||
plugin_settings: Record<string, any>,
|
||||
plugin_param: string,
|
||||
node_name_id: string,
|
||||
input_name: string
|
||||
) {
|
||||
if (plugin_param in plugin_settings) {
|
||||
setInputValue(
|
||||
nodes,
|
||||
prompt,
|
||||
node_name_id,
|
||||
input_name,
|
||||
plugin_settings[plugin_param]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(mode_map).forEach((plugin_param: string) => {
|
||||
const [node_name_id, input_name] = mode_map[plugin_param].split('.')
|
||||
mapPluginInputToComfyInput(
|
||||
plugin_settings,
|
||||
plugin_param,
|
||||
node_name_id,
|
||||
input_name
|
||||
)
|
||||
})
|
||||
|
||||
plugin_settings = await addMissingControlnetSettings(plugin_settings)
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
const unit = plugin_settings['controlnet_units'][i]
|
||||
// one for each controlnet unit
|
||||
Object.keys(controlnet_txt2img_map).forEach(
|
||||
(plugin_param: string) => {
|
||||
let [node_name_id, input_name] =
|
||||
controlnet_txt2img_map[plugin_param].split('.')
|
||||
// if (
|
||||
// node_name_id === 'controlnet_image' ||
|
||||
// node_name_id === 'controlnet_mask'
|
||||
// ) {
|
||||
// // the input images and masks are each in separate nodes
|
||||
// node_name_id = `${node_name_id}_${i + 1}` //ex: 'controlnet_image.image' -> controlnet_image_1.image
|
||||
// } else {
|
||||
// //all other inputs present in the controlnet script
|
||||
// input_name = `${input_name}_${i + 1}` //ex: preprocessor_name -> preprocessor_name_1
|
||||
// }
|
||||
input_name = `${input_name}_${i + 1}` //ex: preprocessor_name -> preprocessor_name_1
|
||||
|
||||
mapPluginInputToComfyInput(
|
||||
unit,
|
||||
plugin_param,
|
||||
node_name_id,
|
||||
input_name
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return prompt
|
||||
}
|
||||
|
||||
async function generateComfyMode(
|
||||
nodes: any[],
|
||||
api_prompt: Record<string, any>,
|
||||
plugin_settings: Record<string, any>,
|
||||
mode_map: Record<string, string>
|
||||
): Promise<{ image_base64_list: string[]; image_url_list: string[] }> {
|
||||
let image_url_list: string[] = []
|
||||
let image_base64_list: string[] = []
|
||||
try {
|
||||
// const controlnet_settings =
|
||||
// mapPluginSettingsToControlNet(plugin_settings)
|
||||
|
||||
// console.log('controlnet_settings:', controlnet_settings)
|
||||
const prompt = await mapPluginSettingsToComfyuiPrompt(
|
||||
nodes,
|
||||
copyJson(api_prompt),
|
||||
plugin_settings,
|
||||
mode_map
|
||||
)
|
||||
const final_prompt = copyJson(prompt)
|
||||
if (!plugin_settings['enable_hr']) {
|
||||
//get node_id
|
||||
const hire_output_node = getNodeByNameId(nodes, 'hires_output')
|
||||
|
||||
delete final_prompt[hire_output_node.id]
|
||||
}
|
||||
|
||||
const separated_output_node_ids: string[] = []
|
||||
const node_id_to_controlnet_unit_index: Record<string, number> = {}
|
||||
for (const [index, unit] of plugin_settings[
|
||||
'controlnet_units'
|
||||
].entries()) {
|
||||
const node_name_id = `preprocessor_output_${index + 1}`
|
||||
const node = getNodeByNameId(nodes, node_name_id)
|
||||
const node_id = node.id.toString()
|
||||
node_id_to_controlnet_unit_index[node_id] = index
|
||||
|
||||
if (unit['comfy_enabled'] === 'disable') {
|
||||
mutePromptNode(nodes, final_prompt, node_name_id)
|
||||
} else if (unit['comfy_enabled'] === 'enable') {
|
||||
separated_output_node_ids.push(node_id)
|
||||
}
|
||||
}
|
||||
// for (let i = 0; i < 3; ++i) {
|
||||
// const unit = plugin_settings['controlnet_units'][i]
|
||||
// if (unit['input_image'] === '') {
|
||||
// mutePromptNode(nodes, final_prompt, `controlnet_image_${i + 1}`)
|
||||
// }
|
||||
// if (unit['mask'] === '') {
|
||||
// mutePromptNode(nodes, final_prompt, `controlnet_mask_${i + 1}`)
|
||||
// }
|
||||
// }
|
||||
console.log('final_prompt: ', final_prompt)
|
||||
const { outputs, separated_outputs } =
|
||||
await comfyui_util.postPromptAndGetBase64JsonResult(
|
||||
final_prompt,
|
||||
separated_output_node_ids
|
||||
)
|
||||
|
||||
if (outputs) {
|
||||
image_url_list = Object.values(outputs).flat()
|
||||
image_base64_list = image_url_list.map((image_url) => {
|
||||
return base64UrlToBase64(image_url)
|
||||
})
|
||||
}
|
||||
if (separated_outputs) {
|
||||
Object.entries(separated_outputs).forEach(([node_id, images]) => {
|
||||
const controlnet_unit_index =
|
||||
node_id_to_controlnet_unit_index[node_id]
|
||||
setControlDetectMapSrc(
|
||||
base64UrlToBase64(images[0]),
|
||||
controlnet_unit_index
|
||||
)
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return { image_base64_list, image_url_list }
|
||||
}
|
||||
async function generateComfyTxt2Img(
|
||||
plugin_settings: any
|
||||
): Promise<{ image_base64_list: string[]; image_url_list: string[] }> {
|
||||
return generateComfyMode(
|
||||
txt2img.nodes,
|
||||
txt2img_api,
|
||||
plugin_settings,
|
||||
txt2img_map
|
||||
)
|
||||
}
|
||||
async function generateComfyImg2Img(
|
||||
plugin_settings: any
|
||||
): Promise<{ image_base64_list: string[]; image_url_list: string[] }> {
|
||||
return generateComfyMode(
|
||||
img2img.nodes,
|
||||
img2img_api,
|
||||
plugin_settings,
|
||||
img2img_map
|
||||
)
|
||||
}
|
||||
async function generateComfyInpaint(
|
||||
plugin_settings: any
|
||||
): Promise<{ image_base64_list: string[]; image_url_list: string[] }> {
|
||||
if ('inpainting_fill' in plugin_settings) {
|
||||
const index = plugin_settings['inpainting_fill']
|
||||
const content_mask_option = [
|
||||
'fill',
|
||||
'original',
|
||||
'latent_noise',
|
||||
'latent_nothing',
|
||||
]
|
||||
plugin_settings['comfy_content_mask'] = content_mask_option[index]
|
||||
|
||||
// const content_mask = [
|
||||
// ['fill', ''],
|
||||
// ['original', 'content_mask_original_output'],
|
||||
// ['latent_noise', 'content_mask_latent_noise_output'],
|
||||
// ['latent_nothing', 'content_mask_latent_nothing_output'],
|
||||
// ]
|
||||
|
||||
// const comfy_node_name_id = content_mask[index][1]
|
||||
// const content_mask_node = getNodeByNameId(
|
||||
// inpaint.nodes,
|
||||
// comfy_node_name_id
|
||||
// )
|
||||
|
||||
// if (index > 0 && index <= 3 && content_mask_node) {
|
||||
// plugin_settings['comfy_content_mask'] = [
|
||||
// content_mask_node.id.toString(),
|
||||
// 0,
|
||||
// ]
|
||||
// }
|
||||
}
|
||||
return generateComfyMode(
|
||||
inpaint.nodes,
|
||||
inpaint_api,
|
||||
plugin_settings,
|
||||
inpaint_map
|
||||
)
|
||||
}
|
||||
|
||||
export default {
|
||||
parseMetadata,
|
||||
getNode,
|
||||
getInput,
|
||||
getLink,
|
||||
getNodesFromLink,
|
||||
getNodeByNameId,
|
||||
mapPluginSettingsToComfyuiPrompt,
|
||||
getPromptNodeByNameId,
|
||||
setInputValue,
|
||||
addMissingSettings,
|
||||
generateComfyTxt2Img,
|
||||
generateComfyImg2Img,
|
||||
generateComfyInpaint,
|
||||
txt2img,
|
||||
txt2img_api,
|
||||
img2img,
|
||||
img2img_api,
|
||||
inpaint,
|
||||
inpaint_api,
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
{
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"50",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"14": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"50": {
|
||||
"inputs": {
|
||||
"add_noise": "enable",
|
||||
"noise_seed": 538408362410054,
|
||||
"steps": 30,
|
||||
"cfg": 7,
|
||||
"sampler_name": "dpmpp_2m",
|
||||
"scheduler": "karras",
|
||||
"start_at_step": 0,
|
||||
"end_at_step": 10000,
|
||||
"return_with_leftover_noise": "disable",
|
||||
"model": [
|
||||
"210",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"211",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"212",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"95",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSamplerAdvanced"
|
||||
},
|
||||
"95": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"192": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"204": {
|
||||
"inputs": {
|
||||
"weight": 0.5,
|
||||
"noise": 0.33,
|
||||
"weight_type": "original",
|
||||
"start_at": 0,
|
||||
"end_at": 1,
|
||||
"ipadapter": [
|
||||
"205",
|
||||
0
|
||||
],
|
||||
"clip_vision": [
|
||||
"206",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"207",
|
||||
0
|
||||
],
|
||||
"model": [
|
||||
"14",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "IPAdapterApply"
|
||||
},
|
||||
"205": {
|
||||
"inputs": {
|
||||
"ipadapter_file": "ip-adapter-plus_sd15.bin"
|
||||
},
|
||||
"class_type": "IPAdapterModelLoader"
|
||||
},
|
||||
"206": {
|
||||
"inputs": {
|
||||
"clip_name": "model.safetensors"
|
||||
},
|
||||
"class_type": "CLIPVisionLoader"
|
||||
},
|
||||
"207": {
|
||||
"inputs": {
|
||||
"interpolation": "LANCZOS",
|
||||
"crop_position": "top",
|
||||
"sharpening": 0.15,
|
||||
"image": [
|
||||
"209",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PrepImageForClipVision"
|
||||
},
|
||||
"209": {
|
||||
"inputs": {
|
||||
"image": "ComfyUI_temp_cqoqp_00001_ (1).png",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"210": {
|
||||
"inputs": {
|
||||
"block_number": 3,
|
||||
"downscale_factor": 1.5,
|
||||
"start_percent": 0,
|
||||
"end_percent": 0.45,
|
||||
"downscale_after_skip": true,
|
||||
"downscale_method": "bicubic",
|
||||
"upscale_method": "bicubic",
|
||||
"model": [
|
||||
"204",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PatchModelAddDownscale"
|
||||
},
|
||||
"211": {
|
||||
"inputs": {
|
||||
"text": "",
|
||||
"clip": [
|
||||
"14",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"212": {
|
||||
"inputs": {
|
||||
"text": "blurry, low quality",
|
||||
"clip": [
|
||||
"14",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
{
|
||||
"1": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"2": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"3": {
|
||||
"inputs": {
|
||||
"ipadapter_file": "ip-adapter-plus_sd15.bin"
|
||||
},
|
||||
"class_type": "IPAdapterModelLoader"
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"clip_name": "model.safetensors"
|
||||
},
|
||||
"class_type": "CLIPVisionLoader"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"image": "ComfyUI_temp_cqoqp_00001_ (1).png",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": "beautiful renaissance girl, detailed",
|
||||
"clip": [
|
||||
"1",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"text": "blurry, horror",
|
||||
"clip": [
|
||||
"1",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"seed": 857545940756658,
|
||||
"steps": 35,
|
||||
"cfg": 5,
|
||||
"sampler_name": "ddim",
|
||||
"scheduler": "ddim_uniform",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"13",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"8",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 4
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"9",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"2",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"filename_prefix": "IPAdapter",
|
||||
"images": [
|
||||
"11",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"weight": 1,
|
||||
"weight_type": "original",
|
||||
"start_at": 0,
|
||||
"end_at": 1,
|
||||
"ipadapter": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"embeds": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"model": [
|
||||
"1",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "IPAdapterApplyEncoded"
|
||||
},
|
||||
"14": {
|
||||
"inputs": {
|
||||
"ipadapter_plus": true,
|
||||
"noise": 0.31,
|
||||
"weight_1": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"weight_2": [
|
||||
"17",
|
||||
0
|
||||
],
|
||||
"weight_3": 1,
|
||||
"weight_4": 1,
|
||||
"clip_vision": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"image_1": [
|
||||
"15",
|
||||
0
|
||||
],
|
||||
"image_2": [
|
||||
"6",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "IPAdapterEncoder"
|
||||
},
|
||||
"15": {
|
||||
"inputs": {
|
||||
"image": "animation-deku-my-hero-academia.jpg",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"Value": 1
|
||||
},
|
||||
"class_type": "Float"
|
||||
},
|
||||
"17": {
|
||||
"inputs": {
|
||||
"Value": 0.38
|
||||
},
|
||||
"class_type": "Float"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
{
|
||||
"2": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"stop_at_clip_layer": -1,
|
||||
"clip": [
|
||||
"32",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPSetLastLayer"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": "embedding:BadDream, ",
|
||||
"clip": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"seed": 888888891,
|
||||
"steps": 8,
|
||||
"cfg": 1.5,
|
||||
"sampler_name": "lcm",
|
||||
"scheduler": "sgm_uniform",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"36",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"38",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"9",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 110
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"2",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"33": {
|
||||
"inputs": {
|
||||
"context_length": 16,
|
||||
"context_stride": 1,
|
||||
"context_overlap": 4,
|
||||
"context_schedule": "uniform",
|
||||
"closed_loop": false
|
||||
},
|
||||
"class_type": "ADE_AnimateDiffUniformContextOptions"
|
||||
},
|
||||
"36": {
|
||||
"inputs": {
|
||||
"model_name": "mm_sd_v15_v2.ckpt",
|
||||
"beta_schedule": "sqrt_linear (AnimateDiff)",
|
||||
"motion_scale": 1,
|
||||
"apply_v2_models_properly": false,
|
||||
"model": [
|
||||
"42",
|
||||
0
|
||||
],
|
||||
"context_options": [
|
||||
"33",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ADE_AnimateDiffLoaderWithContext"
|
||||
},
|
||||
"37": {
|
||||
"inputs": {
|
||||
"frame_rate": 8,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "aaa_readme",
|
||||
"format": "image/gif",
|
||||
"pingpong": false,
|
||||
"save_image": true,
|
||||
"crf": 20,
|
||||
"save_metadata": true,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "aaa_readme_00024.gif",
|
||||
"subfolder": "",
|
||||
"type": "output",
|
||||
"format": "image/gif"
|
||||
}
|
||||
},
|
||||
"images": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VHS_VideoCombine"
|
||||
},
|
||||
"38": {
|
||||
"inputs": {
|
||||
"text": "\"0\" : \"Spring, flowers, smile\",\n\"20\" : \"Spring, flowers, smile\",\n\"30\" : \"Summer, sun, happy, windy\",\n\"50\" : \"Summer, sun, happy, windy\",\n\"60\" : \"Autumn, yellow leaves, laugh\",\n\"80\" : \"Autumn, yellow leaves, laugh\",\n\"90\" : \"Winter, wind, snow, smile, seductive\",\n\"110\" : \"Winter, wind snow, smile, seductive\"",
|
||||
"max_frames": 110,
|
||||
"print_output": false,
|
||||
"pre_text": "25 year old woman, t-shirt",
|
||||
"app_text": "",
|
||||
"start_frame": 0,
|
||||
"pw_a": 0,
|
||||
"pw_b": 0,
|
||||
"pw_c": 0,
|
||||
"pw_d": 0,
|
||||
"clip": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "BatchPromptSchedule"
|
||||
},
|
||||
"41": {
|
||||
"inputs": {
|
||||
"lora_name": "lcm_lora_sd15.safetensors",
|
||||
"strength_model": 1,
|
||||
"strength_clip": 1,
|
||||
"model": [
|
||||
"32",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"32",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "LoraLoader"
|
||||
},
|
||||
"42": {
|
||||
"inputs": {
|
||||
"sampling": "lcm",
|
||||
"zsnr": false,
|
||||
"model": [
|
||||
"41",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ModelSamplingDiscrete"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
{
|
||||
"2": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"3": {
|
||||
"inputs": {
|
||||
"text": "girl astronaut walking on the moon. ",
|
||||
"clip": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"stop_at_clip_layer": -2,
|
||||
"clip": [
|
||||
"32",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPSetLastLayer"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": "(worst quality, low quality: 1.4)",
|
||||
"clip": [
|
||||
"4",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"seed": 888888889,
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "normal",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"27",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"9",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 16
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"10": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"2",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"model_name": "mm_sd_v14.ckpt",
|
||||
"beta_schedule": "sqrt_linear (AnimateDiff)",
|
||||
"motion_scale": 1,
|
||||
"apply_v2_models_properly": false,
|
||||
"model": [
|
||||
"32",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ADE_AnimateDiffLoaderWithContext"
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"ckpt_name": "cardosAnime_v20.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"35": {
|
||||
"inputs": {
|
||||
"frame_rate": 8,
|
||||
"loop_count": 0,
|
||||
"filename_prefix": "aaa_readme",
|
||||
"format": "image/gif",
|
||||
"pingpong": false,
|
||||
"save_image": true,
|
||||
"crf": 20,
|
||||
"save_metadata": false,
|
||||
"videopreview": {
|
||||
"hidden": false,
|
||||
"paused": false,
|
||||
"params": {
|
||||
"filename": "aaa_readme_00022.gif",
|
||||
"subfolder": "",
|
||||
"type": "output",
|
||||
"format": "image/gif"
|
||||
}
|
||||
},
|
||||
"images": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VHS_VideoCombine"
|
||||
},
|
||||
"37": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"10",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"43": {
|
||||
"inputs": {
|
||||
"seed": 927413224602369,
|
||||
"steps": 4,
|
||||
"cfg": 8,
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"num_images": 4,
|
||||
"use_fp16": true,
|
||||
"positive_prompt": "cute cat"
|
||||
},
|
||||
"class_type": "LCM_Sampler"
|
||||
},
|
||||
"44": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"43",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
{
|
||||
"1": {
|
||||
"inputs": {
|
||||
"image": "000662ed61a84c86fc8a3fe69d38a6e2 (1).jpg",
|
||||
"choose file to upload": "image"
|
||||
},
|
||||
"class_type": "LoadImage"
|
||||
},
|
||||
"2": {
|
||||
"inputs": {
|
||||
"left": 112,
|
||||
"top": 112,
|
||||
"right": 104,
|
||||
"bottom": 208,
|
||||
"feathering": 20,
|
||||
"image": [
|
||||
"50",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImagePadForOutpaint"
|
||||
},
|
||||
"3": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"2",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": [
|
||||
"12",
|
||||
2
|
||||
],
|
||||
"height": [
|
||||
"12",
|
||||
1
|
||||
],
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"pixels": [
|
||||
"2",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"7",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"value": [
|
||||
"2",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImpactImageInfo"
|
||||
},
|
||||
"14": {
|
||||
"inputs": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"resize_source": true,
|
||||
"destination": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"source": [
|
||||
"5",
|
||||
0
|
||||
],
|
||||
"mask": [
|
||||
"2",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "LatentCompositeMasked"
|
||||
},
|
||||
"15": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"7",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"19": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"15",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"20": {
|
||||
"inputs": {
|
||||
"strength": 1,
|
||||
"conditioning": [
|
||||
"27",
|
||||
4
|
||||
],
|
||||
"control_net": [
|
||||
"21",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"47",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetApply"
|
||||
},
|
||||
"21": {
|
||||
"inputs": {
|
||||
"control_net_name": "control_v11p_sd15_inpaint_fp16.safetensors"
|
||||
},
|
||||
"class_type": "ControlNetLoader"
|
||||
},
|
||||
"22": {
|
||||
"inputs": {
|
||||
"ckpt_name": "aniverse_v15Pruned.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"23": {
|
||||
"inputs": {
|
||||
"model": [
|
||||
"22",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"22",
|
||||
1
|
||||
],
|
||||
"vae": [
|
||||
"22",
|
||||
2
|
||||
],
|
||||
"positive": [
|
||||
"24",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"25",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ToBasicPipe"
|
||||
},
|
||||
"24": {
|
||||
"inputs": {
|
||||
"text": "",
|
||||
"clip": [
|
||||
"22",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"25": {
|
||||
"inputs": {
|
||||
"text": "nsfw",
|
||||
"clip": [
|
||||
"22",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"27": {
|
||||
"inputs": {
|
||||
"basic_pipe": [
|
||||
"23",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "FromBasicPipe_v2"
|
||||
},
|
||||
"29": {
|
||||
"inputs": {
|
||||
"basic_pipe": [
|
||||
"27",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"20",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "EditBasicPipe"
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"seed": 949895177872699,
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "normal",
|
||||
"denoise": 1,
|
||||
"basic_pipe": [
|
||||
"29",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"62",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImpactKSamplerBasicPipe"
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"30",
|
||||
1
|
||||
],
|
||||
"vae": [
|
||||
"30",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"32": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"31",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"33": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"14",
|
||||
0
|
||||
],
|
||||
"mask": [
|
||||
"2",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "SetLatentNoiseMask"
|
||||
},
|
||||
"47": {
|
||||
"inputs": {
|
||||
"image": [
|
||||
"2",
|
||||
0
|
||||
],
|
||||
"mask": [
|
||||
"2",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "InpaintPreprocessor"
|
||||
},
|
||||
"50": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"scale_by": 0.3,
|
||||
"image": [
|
||||
"1",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ImageScaleBy"
|
||||
},
|
||||
"52": {
|
||||
"inputs": {
|
||||
"clip_vision": [
|
||||
"53",
|
||||
0
|
||||
],
|
||||
"image": [
|
||||
"1",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPVisionEncode"
|
||||
},
|
||||
"53": {
|
||||
"inputs": {
|
||||
"clip_name": "SD1.5/pytorch_model.bin"
|
||||
},
|
||||
"class_type": "CLIPVisionLoader"
|
||||
},
|
||||
"56": {
|
||||
"inputs": {
|
||||
"pixels": [
|
||||
"2",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"7",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEEncode"
|
||||
},
|
||||
"62": {
|
||||
"inputs": {
|
||||
"amount": 2,
|
||||
"samples": [
|
||||
"33",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "RepeatLatentBatch"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": 945794611996037,
|
||||
"steps": 12,
|
||||
"cfg": 8,
|
||||
"sampler_name": "dpmpp_sde",
|
||||
"scheduler": "normal",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"81",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"81",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage"
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"58",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"58",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"60",
|
||||
2
|
||||
],
|
||||
"clip": [
|
||||
"60",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode"
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"11": {
|
||||
"inputs": {
|
||||
"seed": 702670332387358,
|
||||
"steps": 14,
|
||||
"cfg": 8,
|
||||
"sampler_name": "dpmpp_2m",
|
||||
"scheduler": "simple",
|
||||
"denoise": 0.5,
|
||||
"model": [
|
||||
"58",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"81",
|
||||
3
|
||||
],
|
||||
"negative": [
|
||||
"81",
|
||||
4
|
||||
],
|
||||
"latent_image": [
|
||||
"55",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler"
|
||||
},
|
||||
"12": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"13",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage"
|
||||
},
|
||||
"13": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"11",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"57",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode"
|
||||
},
|
||||
"16": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple"
|
||||
},
|
||||
"55": {
|
||||
"inputs": {
|
||||
"upscale_method": "nearest-exact",
|
||||
"scale_by": 2,
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LatentUpscaleBy"
|
||||
},
|
||||
"57": {
|
||||
"inputs": {
|
||||
"vae_name": "vae-ft-mse-840000-ema-pruned.safetensors"
|
||||
},
|
||||
"class_type": "VAELoader"
|
||||
},
|
||||
"58": {
|
||||
"inputs": {
|
||||
"prompt": "<lora:lora_delta_small:0.7> lora_delta girl lora_bright_style girl masterpiece HDR victorian portrait painting of woman, blonde hair, mountain nature, blue sky",
|
||||
"model": [
|
||||
"60",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"98",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"60": {
|
||||
"inputs": {
|
||||
"prompt": "bad hands, text, watermark",
|
||||
"model": [
|
||||
"16",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"98",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "LoadLorasFromPrompt"
|
||||
},
|
||||
"81": {
|
||||
"inputs": {
|
||||
"is_enabled_1": "disable",
|
||||
"preprocessor_name_1": "CannyEdgePreprocessor",
|
||||
"control_net_name_1": "control_lora_rank128_v11p_sd15_canny_fp16.safetensors",
|
||||
"strength_1": 1,
|
||||
"threshold_a_1": 100,
|
||||
"threshold_b_1": 200,
|
||||
"start_percent_1": 0,
|
||||
"end_percent_1": 1,
|
||||
"resolution_1": 512,
|
||||
"is_enabled_2": "disable",
|
||||
"preprocessor_name_2": "OpenposePreprocessor",
|
||||
"control_net_name_2": "control_lora_rank128_v11p_sd15_openpose_fp16.safetensors",
|
||||
"strength_2": 1,
|
||||
"threshold_a_2": 0,
|
||||
"threshold_b_2": 0,
|
||||
"start_percent_2": 0,
|
||||
"end_percent_2": 1,
|
||||
"resolution_2": 512,
|
||||
"is_enabled_3": "disable",
|
||||
"preprocessor_name_3": "InpaintPreprocessor",
|
||||
"control_net_name_3": "control_lora_rank128_v11p_sd15_inpaint_fp16.safetensors",
|
||||
"strength_3": 1,
|
||||
"threshold_a_3": 0,
|
||||
"threshold_b_3": 0,
|
||||
"start_percent_3": 0,
|
||||
"end_percent_3": 1,
|
||||
"resolution_3": 512,
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "ControlNetScript"
|
||||
},
|
||||
"91": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"81",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"92": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"81",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"93": {
|
||||
"inputs": {
|
||||
"images": [
|
||||
"81",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "PreviewImage"
|
||||
},
|
||||
"98": {
|
||||
"inputs": {
|
||||
"stop_at_clip_layer": -1,
|
||||
"clip": [
|
||||
"16",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPSetLastLayer"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,547 @@
|
|||
import { readdirSync, readFileSync } from 'fs'
|
||||
import { requestPost } from '../util/ts/api'
|
||||
|
||||
import { storage } from 'uxp'
|
||||
import { reaction, toJS } from 'mobx'
|
||||
import { AStore } from '../main/astore'
|
||||
|
||||
import comfyapi from './comfyapi'
|
||||
import { base64UrlToBase64 } from '../util/ts/general'
|
||||
import { app } from 'photoshop'
|
||||
export enum InputTypeEnum {
|
||||
NumberField = 'NumberField',
|
||||
TextField = 'TextField',
|
||||
TextArea = 'TextArea',
|
||||
Menu = 'Menu',
|
||||
ImageBase64 = 'ImageBase64',
|
||||
}
|
||||
export interface ValidInput {
|
||||
[key: string]: any
|
||||
value: string | number
|
||||
label: string
|
||||
list?: any[]
|
||||
type: InputTypeEnum
|
||||
id?: string
|
||||
}
|
||||
export interface PhotoshopNode {
|
||||
inputs: ValidInput[]
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface ComfyUIConfig {
|
||||
[key: string]: any
|
||||
checkpoints: string[]
|
||||
samplers: string[]
|
||||
schedulers: string[]
|
||||
}
|
||||
|
||||
export interface ComfyUINode {
|
||||
inputs: any
|
||||
class_type: string
|
||||
}
|
||||
// Assuming the json files are in a directory named 'native_workflows'
|
||||
const dir = 'plugin:/typescripts/comfyui/native_workflows' // specify the directory containing the .json files
|
||||
let workflows2: Record<string, any> = {}
|
||||
readdirSync(dir).forEach((file) => {
|
||||
if (file.endsWith('.json')) {
|
||||
const fileContent = readFileSync(`${dir}/${file}`, 'utf8')
|
||||
const fileNameWithoutExtension = file.slice(0, -5)
|
||||
workflows2[fileNameWithoutExtension] = JSON.parse(fileContent)
|
||||
}
|
||||
})
|
||||
|
||||
export const store = new AStore({
|
||||
comfyui_valid_nodes: {} as any, // comfyui nodes like structure that contain all info necessary to create plugin ui elements
|
||||
uuids: {} as any,
|
||||
|
||||
comfyui_output_images: [] as string[], //store the output images from generation
|
||||
comfyui_output_thumbnail_images: [] as string[], // store thumbnail size images
|
||||
comfyui_config: {} as ComfyUIConfig, // all config data like samplers, checkpoints ...etc
|
||||
workflow_path: '', // the path of an image that contains prompt information
|
||||
workflow_dir_path: '', // the path of the directory that contains all workflow files
|
||||
// workflows_paths: [] as string[],
|
||||
// workflows_names: [] as string[],
|
||||
workflows: {} as any,
|
||||
selected_workflow_name: '', // the selected workflow from the workflow menu
|
||||
current_prompt: {} as any, // current prompt extracted from the workflow
|
||||
thumbnail_image_size: 100,
|
||||
load_image_nodes: {} as any, //our custom loadImageBase64 nodes, we need to substitute comfyui LoadImage nodes with before generating a prompt
|
||||
// load_image_base64_strings: {} as any, //images the user added to the plugin comfy ui
|
||||
object_info: undefined as any,
|
||||
current_prompt2: {} as any,
|
||||
current_prompt2_output: {} as any,
|
||||
output_thumbnail_image_size: {} as Record<string, number>,
|
||||
|
||||
uploaded_images_base64_url: [] as string[],
|
||||
current_uploaded_image: {} as Record<string, string>, //key: node_id, value: base64_url; only used in UI to show the selected images for LoadImage nodes
|
||||
current_uploaded_video: {} as Record<string, string>,
|
||||
uploaded_images_list: [] as string[], // store an array of all images in the comfy's input directory
|
||||
uploaded_video_list: [] as string[], // store the name of .gif and .mp4 videos in comfy's input directory and subcategories
|
||||
nodes_order: [] as string[], // nodes with smaller index will be rendered first,
|
||||
can_edit_nodes: false as boolean,
|
||||
nodes_label: {} as Record<string, string>,
|
||||
|
||||
workflows2: workflows2 as Record<string, any>,
|
||||
user_custom_workflow: {} as Record<string, any>,
|
||||
progress_value: 0,
|
||||
is_random_seed: {} as Record<string, boolean>,
|
||||
last_moved: undefined as string | undefined, // the last node that has been moved in the edit mode
|
||||
|
||||
base64_to_uploaded_images_names: {} as Record<string, any>,
|
||||
can_generate: true as boolean,
|
||||
})
|
||||
|
||||
interface Workflow {}
|
||||
export function getNodes(workflow: Workflow) {
|
||||
// Object.values(workflow).forEach((node) => {
|
||||
// console.log(node.class_type)
|
||||
// })
|
||||
return Object.entries(workflow)
|
||||
}
|
||||
|
||||
export enum ComfyInputType {
|
||||
TextField = 'TextField',
|
||||
TextArea = 'TextArea',
|
||||
Menu = 'Menu',
|
||||
Number = 'Number',
|
||||
Slider = 'Slider',
|
||||
BigNumber = 'BigNumber',
|
||||
TextFieldNumber = 'TextFieldNumber',
|
||||
Skip = 'Skip',
|
||||
Seed = 'Seed',
|
||||
CheckBox = 'CheckBox',
|
||||
}
|
||||
export enum ComfyNodeType {
|
||||
LoadImage = 'LoadImage',
|
||||
LoadVideo = 'LoadVideo',
|
||||
Normal = 'Normal',
|
||||
Skip = 'Skip',
|
||||
}
|
||||
|
||||
interface ComfyOutputImage {
|
||||
filename: string
|
||||
subfolder: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export function getNodeType(node_name: any) {
|
||||
let node_type: ComfyNodeType = ComfyNodeType.Normal
|
||||
switch (node_name) {
|
||||
case 'LoadImage':
|
||||
node_type = ComfyNodeType.LoadImage
|
||||
break
|
||||
case 'LoadVideo':
|
||||
node_type = ComfyNodeType.LoadVideo
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
return node_type
|
||||
}
|
||||
export function parseComfyInput(
|
||||
name: string,
|
||||
input_info: any,
|
||||
prompt_value: any // the default value, set in the prompt api
|
||||
): {
|
||||
type: ComfyInputType
|
||||
config: any
|
||||
} {
|
||||
let input_type: ComfyInputType = ComfyInputType.Skip
|
||||
let input_config = input_info?.[1] || void 0
|
||||
if (input_info === undefined) {
|
||||
return { type: input_type, config: input_config }
|
||||
}
|
||||
|
||||
try {
|
||||
const value = input_info[0]
|
||||
|
||||
if (
|
||||
(name === 'seed' || name === 'noise_seed') &&
|
||||
!Array.isArray(prompt_value)
|
||||
) {
|
||||
input_type = ComfyInputType.Seed // similar to big number
|
||||
input_config = input_info[1]
|
||||
} else if (typeof value === 'string') {
|
||||
if (value === 'FLOAT' && !Array.isArray(prompt_value)) {
|
||||
if (Number.isSafeInteger(input_config?.max)) {
|
||||
input_type = ComfyInputType.Slider
|
||||
input_config = input_info[1]
|
||||
} else {
|
||||
input_type = ComfyInputType.TextFieldNumber
|
||||
input_config = input_info[1]
|
||||
}
|
||||
} else if (value === 'INT' && !Array.isArray(prompt_value)) {
|
||||
if (input_info[1].max > Number.MAX_SAFE_INTEGER) {
|
||||
input_type = ComfyInputType.BigNumber
|
||||
input_config = input_info[1]
|
||||
} else {
|
||||
input_type = ComfyInputType.TextFieldNumber
|
||||
input_config = input_info[1]
|
||||
}
|
||||
} else if (value === 'STRING' && !Array.isArray(prompt_value)) {
|
||||
if (input_info[1]?.multiline) {
|
||||
input_type = ComfyInputType.TextArea
|
||||
input_config = input_info[1]
|
||||
} else {
|
||||
input_type = ComfyInputType.TextField
|
||||
input_config = input_info[1]
|
||||
}
|
||||
} else if (value === 'BOOLEAN' && !Array.isArray(prompt_value)) {
|
||||
input_type = ComfyInputType.CheckBox
|
||||
input_config = input_info[1]
|
||||
}
|
||||
} else if (Array.isArray(value)) {
|
||||
input_type = ComfyInputType.Menu
|
||||
input_config = value
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`name:${name},
|
||||
input_info:${input_info},
|
||||
prompt_value:${prompt_value}`,
|
||||
e
|
||||
)
|
||||
}
|
||||
return { type: input_type, config: input_config }
|
||||
}
|
||||
|
||||
export function makeHtmlInput() {}
|
||||
|
||||
async function getHistory(prompt_id: string) {
|
||||
while (true) {
|
||||
const res = await comfyapi.comfy_api.queue()
|
||||
if (res.queue_pending.length || res.queue_running.length) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
}
|
||||
const history = await comfyapi.comfy_api.getHistory(prompt_id)
|
||||
return history
|
||||
}
|
||||
export async function postPromptAndGetBase64JsonResult(
|
||||
prompt: Record<string, any>,
|
||||
separated_output_nodes: string[] = []
|
||||
): Promise<{
|
||||
outputs: Record<string, any> | undefined
|
||||
separated_outputs: Record<string, any> | undefined
|
||||
}> {
|
||||
try {
|
||||
const res = await comfyapi.comfy_api.prompt(prompt)
|
||||
if (!res) {
|
||||
throw new Error(
|
||||
`Unable to establish a connection to ComfyUI at the provided address: ${comfyapi.comfy_api.comfy_url}. Please ensure that ComfyUI is online and the URL is correct.`
|
||||
)
|
||||
}
|
||||
if (res.error) {
|
||||
const readable_error = comfyapi.comfy_api.getReadableError(res)
|
||||
throw new Error(readable_error)
|
||||
}
|
||||
const prompt_id = res.prompt_id
|
||||
const history = await getHistory(prompt_id)
|
||||
const promptInfo = history[prompt_id]
|
||||
if (Object.keys(promptInfo.outputs).length === 0) {
|
||||
throw new Error(
|
||||
`No images were generated. Please check the ComfyUI console for potential errors.`
|
||||
)
|
||||
}
|
||||
|
||||
const { outputs, separated_outputs } =
|
||||
await mapComfyOutputToStoreOutput(
|
||||
promptInfo.outputs,
|
||||
separated_output_nodes
|
||||
)
|
||||
// // [4][0] for output id.
|
||||
// const fileName = promptInfo.outputs[promptInfo.prompt[4][0]].images[0].filename
|
||||
// const resultB64 = await ComfyApi.view(this, fileName);
|
||||
// resultImages.push(resultB64)
|
||||
// if (option.imageFinishCallback) {
|
||||
// try { option.imageFinishCallback(resultB64, index) } catch (e) { }
|
||||
// }
|
||||
// }
|
||||
return { outputs, separated_outputs }
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
app.showAlert(`${e}`)
|
||||
return { outputs: undefined, separated_outputs: undefined }
|
||||
}
|
||||
}
|
||||
export const getFileFormat = (fileName: string): string =>
|
||||
fileName.includes('.') ? fileName.split('.').pop()! : ''
|
||||
|
||||
export async function base64UrlFromComfy({
|
||||
filename,
|
||||
type,
|
||||
subfolder,
|
||||
}: ComfyOutputImage) {
|
||||
const base64 = await comfyapi.comfy_api.view(filename, type, subfolder)
|
||||
return base64Url(base64, getFileFormat(filename))
|
||||
}
|
||||
export function base64UrlFromFileName(base64: string, filename: string) {
|
||||
return base64Url(base64, getFileFormat(filename))
|
||||
}
|
||||
export function base64Url(base64: string, format: string = 'png') {
|
||||
return `data:image/${format};base64,${base64}`
|
||||
}
|
||||
export function generatePrompt(prompt: Record<string, any>) {
|
||||
prompt
|
||||
}
|
||||
export function updateOutput(output: any, output_store_obj: any) {
|
||||
// store.data.current_prompt2_output[26] = [image, image]
|
||||
output_store_obj = output
|
||||
}
|
||||
|
||||
export async function mapComfyOutputToStoreOutput(
|
||||
comfy_output: Record<string, any>,
|
||||
separated_output_nodes: string[] = []
|
||||
) {
|
||||
const outputs: Record<string, any> = {}
|
||||
const separated_outputs: Record<string, any> = {}
|
||||
|
||||
for (let key in comfy_output) {
|
||||
let base64_url_list = await Promise.all(
|
||||
(Object.values(comfy_output[key]).flat() as ComfyOutputImage[]).map(
|
||||
async (output: ComfyOutputImage) => {
|
||||
try {
|
||||
if (['png'].includes(extractFormat(output.filename))) {
|
||||
return await base64UrlFromComfy(output)
|
||||
} else if (
|
||||
['gif'].includes(extractFormat(output.filename))
|
||||
) {
|
||||
const url = `${comfyapi.comfy_api.comfy_url}/view?subfolder=${output.subfolder}&type=${output.type}&filename=${output.filename}`
|
||||
return url
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(output, e)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
base64_url_list = base64_url_list.filter((item) => item !== '') // Filter out empty strings
|
||||
|
||||
if (separated_output_nodes.includes(key)) {
|
||||
separated_outputs[key] = [
|
||||
...(separated_outputs[key] || []),
|
||||
...base64_url_list,
|
||||
]
|
||||
} else {
|
||||
outputs[key] = [...(outputs[key] || []), ...base64_url_list]
|
||||
}
|
||||
}
|
||||
|
||||
return { outputs, separated_outputs }
|
||||
}
|
||||
|
||||
interface LooseObject {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
function isSameStructure(obj1: LooseObject, obj2: LooseObject): boolean {
|
||||
// Get keys
|
||||
const keys1 = Object.keys(obj1)
|
||||
const keys2 = Object.keys(obj2)
|
||||
|
||||
// Check if both objects have the same number of keys
|
||||
if (keys1.length !== keys2.length) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if all keys in obj1 exist in obj2 and have the same structure
|
||||
for (let i = 0; i < keys1.length; i++) {
|
||||
const key = keys1[i]
|
||||
|
||||
// Check if the key exists in obj2
|
||||
if (!obj2.hasOwnProperty(key)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the value of this key is an object, check their structure recursively
|
||||
if (
|
||||
typeof obj1[key] === 'object' &&
|
||||
obj1[key] !== null &&
|
||||
typeof obj2[key] === 'object' &&
|
||||
obj2[key] !== null
|
||||
) {
|
||||
if (!isSameStructure(obj1[key], obj2[key])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all checks passed, the structures are the same
|
||||
return true
|
||||
}
|
||||
|
||||
function extractFormat(input: string) {
|
||||
let format: string = ''
|
||||
if (input.includes('data:')) {
|
||||
// Case for dataURL
|
||||
format = input.split(':')[1].split(';')[0].split('/')[1]
|
||||
} else if (input.includes('.')) {
|
||||
// Case for file name with extension
|
||||
format = input.split('.').pop() || ''
|
||||
} else {
|
||||
throw `input doesn't have an extension. input:${input}`
|
||||
}
|
||||
return format
|
||||
}
|
||||
|
||||
async function uploadImagePost(
|
||||
buffer: any,
|
||||
file_name: string,
|
||||
subfolder: string = 'auto-photoshop-plugin'
|
||||
) {
|
||||
try {
|
||||
const full_url = comfyapi.comfy_api.comfy_url + '/upload/image'
|
||||
var formData = new FormData()
|
||||
|
||||
formData.append('image', buffer, file_name)
|
||||
formData.append('subfolder', subfolder)
|
||||
var requestOptions = {
|
||||
method: 'POST',
|
||||
// header: myHeaders,
|
||||
body: formData,
|
||||
}
|
||||
//@ts-ignore
|
||||
const res = await fetch(full_url, requestOptions)
|
||||
|
||||
console.log(res.status, full_url)
|
||||
|
||||
const contentType = res.headers.get('Content-Type')
|
||||
|
||||
if (contentType?.indexOf('json') != -1) {
|
||||
return res.json()
|
||||
} else {
|
||||
if (res.status == 200) {
|
||||
return res.arrayBuffer()
|
||||
} else {
|
||||
return res.text()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
async function uploadImage(b_from_disk = false, imgBase64: string) {
|
||||
try {
|
||||
let content, name
|
||||
if (b_from_disk) {
|
||||
const res = await readFile()
|
||||
content = res.content
|
||||
name = res.name
|
||||
} else {
|
||||
//from canvas
|
||||
//@ts-ignore
|
||||
const buffer = _base64ToArrayBuffer(imgBase64)
|
||||
content = buffer
|
||||
name = 'buffer.png'
|
||||
}
|
||||
|
||||
// console.log('content: ', content)
|
||||
// console.log('name: ', name)
|
||||
|
||||
const uploaded_image = await uploadImagePost(content, name, '')
|
||||
return uploaded_image
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function readFile() {
|
||||
const entry = await storage.localFileSystem.getFileForOpening() // Prompts the user to select a file
|
||||
// const contents = await entry.read('binary') // Reads the file as a string
|
||||
const contents = await entry.read({
|
||||
format: storage.formats.binary,
|
||||
})
|
||||
return { content: contents, name: entry.name }
|
||||
}
|
||||
|
||||
function getRandomBigIntApprox(min: bigint, max: bigint): bigint {
|
||||
min = BigInt(min)
|
||||
max = BigInt(max)
|
||||
const range = Number(max - min)
|
||||
const rand = Math.floor(Math.random() * range)
|
||||
return BigInt(rand) + min
|
||||
}
|
||||
function runRandomSeedScript() {
|
||||
Object.entries(toJS(store.data.is_random_seed)).forEach(
|
||||
([node_id, is_random]) => {
|
||||
if (is_random) {
|
||||
const random_seed: bigint = getRandomBigIntApprox(
|
||||
0n,
|
||||
18446744073709552000n
|
||||
)
|
||||
Object.keys(store.data.current_prompt2[node_id].inputs).forEach(
|
||||
(name: string) => {
|
||||
if (['seed', 'noise_seed'].includes(name)) {
|
||||
store.data.current_prompt2[node_id].inputs[name] =
|
||||
random_seed.toString()
|
||||
// Usage
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
async function maskExpansion(
|
||||
base64_mask: string,
|
||||
expansion: number,
|
||||
blur: number
|
||||
) {
|
||||
const prompt = {
|
||||
'1': {
|
||||
inputs: {
|
||||
mask: base64_mask,
|
||||
expansion: expansion,
|
||||
blur: blur,
|
||||
},
|
||||
class_type: 'MaskExpansion',
|
||||
},
|
||||
'6': {
|
||||
inputs: {
|
||||
images: ['1', 0],
|
||||
},
|
||||
class_type: 'PreviewImage',
|
||||
},
|
||||
}
|
||||
try {
|
||||
const { outputs, separated_outputs } =
|
||||
await postPromptAndGetBase64JsonResult(prompt)
|
||||
if (outputs) {
|
||||
const expanded_mask = outputs['6'][0]
|
||||
return base64UrlToBase64(expanded_mask)
|
||||
}
|
||||
// html_manip.setInitImageMaskSrc(expanded_mask)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return base64_mask
|
||||
}
|
||||
export default {
|
||||
uploadImage,
|
||||
uploadImagePost,
|
||||
getNodes,
|
||||
parseComfyInput,
|
||||
getNodeType,
|
||||
base64Url,
|
||||
getFileFormat,
|
||||
base64UrlFromComfy,
|
||||
generatePrompt,
|
||||
updateOutput,
|
||||
getHistory,
|
||||
mapComfyOutputToStoreOutput,
|
||||
postPromptAndGetBase64JsonResult,
|
||||
isSameStructure,
|
||||
extractFormat,
|
||||
getRandomBigIntApprox,
|
||||
runRandomSeedScript,
|
||||
maskExpansion,
|
||||
workflows2,
|
||||
ComfyInputType,
|
||||
ComfyNodeType,
|
||||
store,
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
PreviewSvg,
|
||||
SpSliderWithLabel,
|
||||
SliderType,
|
||||
SearchableMenu,
|
||||
} from '../util/elements'
|
||||
import ControlNetStore, { ControlnetMode, controlnetModes } from './store'
|
||||
import { mapRange, versionCompare } from './util'
|
||||
|
|
@ -135,18 +136,12 @@ export default class ControlNetUnit extends React.Component<
|
|||
storeData.model = filters.default_model
|
||||
}
|
||||
}
|
||||
onPreprocsesorChange(
|
||||
event: any,
|
||||
{ index, item }: { index: number; item: string }
|
||||
) {
|
||||
onPreprocsesorChange(item: string) {
|
||||
const storeData =
|
||||
this.props.appState.controlNetUnitData[this.props.index]
|
||||
storeData.module = item
|
||||
}
|
||||
onModelChange(
|
||||
event: any,
|
||||
{ index, item }: { index: number; item: string }
|
||||
) {
|
||||
onModelChange(item: string) {
|
||||
const storeData =
|
||||
this.props.appState.controlNetUnitData[this.props.index]
|
||||
storeData.model = item
|
||||
|
|
@ -806,7 +801,7 @@ export default class ControlNetUnit extends React.Component<
|
|||
style={{ display: 'flex' }}
|
||||
>
|
||||
<div style={{ width: '50%', display: 'flex' }}>
|
||||
<SpMenu
|
||||
{/* <SpMenu
|
||||
onChange={this.onPreprocsesorChange.bind(this)}
|
||||
id={`mModulesMenuControlNet_${this.props.index}`}
|
||||
items={storeData.module_list || ['none']}
|
||||
|
|
@ -815,11 +810,27 @@ export default class ControlNetUnit extends React.Component<
|
|||
storeData.module
|
||||
)}
|
||||
style={{ width: '100%' }}
|
||||
/> */}
|
||||
<SearchableMenu
|
||||
allItems={storeData.module_list || ['none']}
|
||||
placeholder={Locale('Select Module')}
|
||||
selected_item={storeData.module}
|
||||
onSelectItemFailure={() => {
|
||||
const default_value =
|
||||
// storeData.module_list[0] || 'None'
|
||||
'None'
|
||||
|
||||
storeData.module = default_value
|
||||
return default_value
|
||||
}}
|
||||
onChange={(item: any) => {
|
||||
this.onPreprocsesorChange(item)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!pd.model_free && (
|
||||
<div style={{ width: '50%', display: 'flex' }}>
|
||||
<SpMenu
|
||||
{/* <SpMenu
|
||||
onChange={this.onModelChange.bind(this)}
|
||||
id={`mModelsMenuControlNet_${this.props.index}`}
|
||||
items={storeData.model_list || []}
|
||||
|
|
@ -828,6 +839,21 @@ export default class ControlNetUnit extends React.Component<
|
|||
storeData.model
|
||||
)}
|
||||
style={{ width: '100%' }}
|
||||
/> */}
|
||||
<SearchableMenu
|
||||
allItems={storeData.model_list || ['none']}
|
||||
placeholder={Locale('Selec Model')}
|
||||
selected_item={storeData.model}
|
||||
onSelectItemFailure={() => {
|
||||
const default_value =
|
||||
// storeData.model_list[0] || 'None'
|
||||
'None'
|
||||
storeData.model = default_value
|
||||
return default_value
|
||||
}}
|
||||
onChange={(item: any) => {
|
||||
this.onModelChange(item)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { toJS } from 'mobx'
|
||||
import { setControlImageSrc } from '../../utility/html_manip'
|
||||
// import { session_ts } from '../entry'
|
||||
// import * as session_ts from '../session/session'
|
||||
import { store as session_store } from '../session/session_store'
|
||||
import { Enum, api, python_replacement } from '../util/oldSystem'
|
||||
import { Enum, api, io, python_replacement } from '../util/oldSystem'
|
||||
import { GenerationModeEnum } from '../util/ts/enum'
|
||||
import store, {
|
||||
DefaultControlNetUnitData,
|
||||
|
|
@ -14,6 +15,40 @@ const { getExtensionUrl } = python_replacement
|
|||
declare const g_sd_config_obj: any
|
||||
declare let g_sd_url: string
|
||||
|
||||
function convertComfyModuleDetailsToPluginModuleDetails(
|
||||
comfy_module_details: Record<string, any>
|
||||
) {
|
||||
let outputJson: Record<string, any> = {}
|
||||
for (let preprocessorName in comfy_module_details) {
|
||||
let preprocessorConfig = comfy_module_details[preprocessorName]
|
||||
let sliders = []
|
||||
if (preprocessorConfig.resolution) {
|
||||
sliders.push({
|
||||
name: `${preprocessorName} Resolution`,
|
||||
value: preprocessorConfig.resolution,
|
||||
min: 64,
|
||||
max: 2048,
|
||||
})
|
||||
}
|
||||
if (preprocessorConfig.param_config) {
|
||||
for (let paramName in preprocessorConfig.param_config) {
|
||||
let paramConfig = preprocessorConfig.param_config[paramName]
|
||||
sliders.push({
|
||||
name: `${paramName}`,
|
||||
value: preprocessorConfig[paramName],
|
||||
min: paramConfig.min,
|
||||
max: paramConfig.max,
|
||||
})
|
||||
}
|
||||
}
|
||||
outputJson[preprocessorName] = {
|
||||
model_free: false,
|
||||
sliders: sliders,
|
||||
}
|
||||
}
|
||||
return outputJson
|
||||
}
|
||||
|
||||
async function requestControlNetPreprocessors() {
|
||||
const control_net_json = await api.requestGet(
|
||||
`${g_sd_url}/controlnet/module_list?alias_names=true`
|
||||
|
|
@ -111,6 +146,38 @@ async function initializeControlNetTab(controlnet_max_models: number) {
|
|||
console.warn(e)
|
||||
}
|
||||
}
|
||||
async function initializeControlNetTabComfyUI(
|
||||
controlnet_max_models: number,
|
||||
controlnet_models: string[],
|
||||
preprocessor_list: string[],
|
||||
preprocessorDetail: Record<string, any>
|
||||
) {
|
||||
store.maxControlNet = controlnet_max_models || store.maxControlNet
|
||||
// store.controlnetApiVersion = await requestControlNetApiVersion()
|
||||
|
||||
try {
|
||||
const models = controlnet_models
|
||||
store.supportedModels = models || []
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
try {
|
||||
store.supportedPreprocessors = preprocessor_list || []
|
||||
|
||||
store.preprocessorDetail =
|
||||
convertComfyModuleDetailsToPluginModuleDetails(preprocessorDetail)
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
try {
|
||||
store.controlNetUnitData.forEach((unitData) => {
|
||||
unitData.module_list = store.supportedPreprocessors
|
||||
unitData.model_list = store.supportedModels
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}
|
||||
|
||||
function getEnableControlNet(index: number) {
|
||||
if (typeof index == 'undefined')
|
||||
|
|
@ -119,24 +186,33 @@ function getEnableControlNet(index: number) {
|
|||
)
|
||||
else return store.controlNetUnitData[index || 0].enabled
|
||||
}
|
||||
function mapPluginSettingsToControlNet(plugin_settings: any) {
|
||||
async function mapPluginSettingsToControlNet(plugin_settings: any) {
|
||||
const ps = plugin_settings // for shortness
|
||||
let controlnet_units: any[] = []
|
||||
function getControlNetInputImage(index: number) {
|
||||
const controlNetUnits = store.controlNetUnitData
|
||||
async function getControlNetInputImage(index: number) {
|
||||
try {
|
||||
const b_sync_input_image =
|
||||
store.controlNetUnitData[index].auto_image
|
||||
let input_image = store.controlNetUnitData[index].input_image
|
||||
const b_sync_input_image = controlNetUnits[index].auto_image
|
||||
let input_image = controlNetUnits[index].input_image
|
||||
if (
|
||||
b_sync_input_image &&
|
||||
[GenerationModeEnum.Txt2Img].includes(session_store.data.mode)
|
||||
) {
|
||||
//conditions: 1) txt2img mode 2)auto image on 3)first generation of session
|
||||
|
||||
input_image = session_store.data.controlnet_input_image ?? ''
|
||||
store.controlNetUnitData[index].input_image = input_image
|
||||
store.controlNetUnitData[index].selection_info =
|
||||
plugin_settings.selection_info
|
||||
if (
|
||||
session_store.data.generation_number === 1 &&
|
||||
session_store.data.controlnet_input_image === ''
|
||||
) {
|
||||
session_store.data.controlnet_input_image =
|
||||
await io.getImg2ImgInitImage()
|
||||
}
|
||||
if (session_store.data.controlnet_input_image !== '') {
|
||||
input_image = session_store.data.controlnet_input_image
|
||||
controlNetUnits[index].input_image = input_image
|
||||
controlNetUnits[index].selection_info =
|
||||
plugin_settings.selection_info
|
||||
}
|
||||
}
|
||||
if (
|
||||
b_sync_input_image &&
|
||||
|
|
@ -149,13 +225,10 @@ function mapPluginSettingsToControlNet(plugin_settings: any) {
|
|||
) {
|
||||
// img2img mode
|
||||
input_image = session_store.data.init_image
|
||||
store.controlNetUnitData[index].input_image = input_image
|
||||
store.controlNetUnitData[index].selection_info =
|
||||
controlNetUnits[index].input_image = input_image
|
||||
controlNetUnits[index].selection_info =
|
||||
plugin_settings.selection_info
|
||||
} else if (
|
||||
b_sync_input_image &&
|
||||
store.controlNetUnitData[index].enabled
|
||||
) {
|
||||
} else if (b_sync_input_image && controlNetUnits[index].enabled) {
|
||||
//txt2img mode
|
||||
}
|
||||
|
||||
|
|
@ -175,9 +248,9 @@ function mapPluginSettingsToControlNet(plugin_settings: any) {
|
|||
//maskless mode
|
||||
} else {
|
||||
//mask related mode
|
||||
store.controlNetUnitData[index].mask = '' // use the mask from the sd mode
|
||||
controlNetUnits[index].mask = '' // use the mask from the sd mode
|
||||
}
|
||||
return store.controlNetUnitData[index].mask
|
||||
return controlNetUnits[index].mask
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
|
|
@ -185,30 +258,29 @@ function mapPluginSettingsToControlNet(plugin_settings: any) {
|
|||
for (let index = 0; index < store.maxControlNet; index++) {
|
||||
controlnet_units[index] = {
|
||||
enabled: getEnableControlNet(index),
|
||||
input_image: getControlNetInputImage(index),
|
||||
input_image: await getControlNetInputImage(index),
|
||||
mask: getControlNetMask(index),
|
||||
module: store.controlNetUnitData[index].module,
|
||||
model: store.controlNetUnitData[index].model,
|
||||
weight: store.controlNetUnitData[index].weight,
|
||||
module: controlNetUnits[index].module,
|
||||
model: controlNetUnits[index].model,
|
||||
weight: controlNetUnits[index].weight,
|
||||
resize_mode: 'Crop and Resize',
|
||||
lowvram: store.controlNetUnitData[index].lowvram,
|
||||
processor_res: store.controlNetUnitData[index].processor_res || 512,
|
||||
threshold_a: store.controlNetUnitData[index].threshold_a,
|
||||
threshold_b: store.controlNetUnitData[index].threshold_b,
|
||||
lowvram: controlNetUnits[index].lowvram,
|
||||
processor_res: controlNetUnits[index].processor_res || 512,
|
||||
threshold_a: controlNetUnits[index].threshold_a,
|
||||
threshold_b: controlNetUnits[index].threshold_b,
|
||||
// guidance: ,
|
||||
guidance_start: store.controlNetUnitData[index].guidance_start,
|
||||
guidance_end: store.controlNetUnitData[index].guidance_end,
|
||||
guidance_start: controlNetUnits[index].guidance_start,
|
||||
guidance_end: controlNetUnits[index].guidance_end,
|
||||
}
|
||||
if (store.controlnetApiVersion > 1) {
|
||||
//new controlnet v2
|
||||
controlnet_units[index].control_mode =
|
||||
store.controlNetUnitData[index].control_mode
|
||||
controlNetUnits[index].control_mode
|
||||
controlnet_units[index].pixel_perfect =
|
||||
store.controlNetUnitData[index].pixel_perfect
|
||||
controlNetUnits[index].pixel_perfect
|
||||
} else {
|
||||
// old controlnet v1
|
||||
controlnet_units[index].guessmode =
|
||||
store.controlNetUnitData[index].guessmode
|
||||
controlnet_units[index].guessmode = controlNetUnits[index].guessmode
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,6 +356,7 @@ export {
|
|||
requestControlNetMaxUnits,
|
||||
requestControlNetFiltersKeywords,
|
||||
initializeControlNetTab,
|
||||
initializeControlNetTabComfyUI,
|
||||
getEnableControlNet,
|
||||
mapPluginSettingsToControlNet,
|
||||
getControlNetMaxModelsNumber,
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ export * as control_net from './controlnet/entry'
|
|||
export * as after_detailer_script from './after_detailer/after_detailer'
|
||||
export * as ultimate_sd_upscaler from './ultimate_sd_upscaler/ultimate_sd_upscaler'
|
||||
export * as scripts from './ultimate_sd_upscaler/scripts'
|
||||
export * as main from './main/main'
|
||||
|
||||
export * as controlnet_main from './controlnet/main'
|
||||
export * as logger from './util/logger'
|
||||
export * as image_search from './image_search/image_search'
|
||||
export * as history from './history/history'
|
||||
export * as viewer from './viewer/viewer'
|
||||
export { default as viewer_util } from './viewer/viewer_util'
|
||||
export * as session_ts from './session/session'
|
||||
export { store as session_store } from './session/session_store'
|
||||
export { store as sd_tab_store } from './sd_tab/util'
|
||||
|
|
@ -37,5 +38,10 @@ export * as stores from './stores'
|
|||
|
||||
export { default as lexica } from './lexical/lexical'
|
||||
export * as api_ts from './util/ts/api'
|
||||
export * as comfyui from './comfyui/comfyui'
|
||||
export { toJS } from 'mobx'
|
||||
export { default as node_fs } from 'fs'
|
||||
export { default as comfyui_util } from './comfyui/util'
|
||||
export { default as comfyui_main_ui } from './comfyui/main_ui'
|
||||
|
||||
export { default as comfyapi } from './comfyui/comfyapi'
|
||||
|
|
|
|||
|
|
@ -5,7 +5,13 @@ import { observer } from 'mobx-react'
|
|||
|
||||
import { GenerationModeEnum, ScriptMode } from '../util/ts/enum'
|
||||
import { reaction } from 'mobx'
|
||||
import { SpCheckBox, SpMenu, SpSlider, SpTextfield } from '../util/elements'
|
||||
import {
|
||||
SearchableMenu,
|
||||
SpCheckBox,
|
||||
SpMenu,
|
||||
SpSlider,
|
||||
SpTextfield,
|
||||
} from '../util/elements'
|
||||
import { ErrorBoundary } from '../util/errorBoundary'
|
||||
import { Collapsible } from '../util/collapsible'
|
||||
|
||||
|
|
@ -32,6 +38,8 @@ import {
|
|||
onHeightSliderInput,
|
||||
heightSliderOnChangeEventHandler,
|
||||
loadPresetSettings,
|
||||
isHiResMode,
|
||||
comfy_mask_content_config,
|
||||
} from './util'
|
||||
import { general } from '../util/oldSystem'
|
||||
import { requestSwapModel, setInpaintMaskWeight } from '../util/ts/sdapi'
|
||||
|
|
@ -44,6 +52,7 @@ import { getExpandedMask } from '../session/session'
|
|||
import { mapRange } from '../controlnet/util'
|
||||
|
||||
import { store as preset_store } from '../preset/shared_ui_preset'
|
||||
import Locale from '../locale/locale'
|
||||
|
||||
declare let g_version: string
|
||||
|
||||
|
|
@ -96,6 +105,22 @@ const Modes = observer(() => {
|
|||
>
|
||||
Lasso Mode
|
||||
</SpCheckBox>
|
||||
<SpCheckBox
|
||||
style={{
|
||||
marginLeft: '10px',
|
||||
display: store.data.is_lasso_mode
|
||||
? void 0
|
||||
: 'none',
|
||||
}}
|
||||
onChange={() => {
|
||||
helper_store.data.make_square =
|
||||
!helper_store.data.make_square
|
||||
}}
|
||||
checked={helper_store.data.make_square}
|
||||
// id={`chEnableControlNet_${this.props.index}`}
|
||||
>
|
||||
Make Square
|
||||
</SpCheckBox>
|
||||
|
||||
<SpSlider
|
||||
show-value="false"
|
||||
|
|
@ -148,12 +173,9 @@ class SDTab extends React.Component<{}> {
|
|||
async componentDidMount() {
|
||||
try {
|
||||
await refreshUI()
|
||||
await refreshModels()
|
||||
await initPlugin()
|
||||
helper_store.data.loras = await requestLoraModels()
|
||||
|
||||
initInitMaskElement()
|
||||
helper_store.data.hr_upscaler_list =
|
||||
await requestGetHiResUpscalers()
|
||||
const btnSquareClass = document.getElementsByClassName('btnSquare')
|
||||
//REFACTOR: move to events.js
|
||||
for (let btnSquareButton of btnSquareClass) {
|
||||
|
|
@ -199,66 +221,85 @@ class SDTab extends React.Component<{}> {
|
|||
}
|
||||
return (
|
||||
<div>
|
||||
<div id="menu-bar-container" style={styles.menuBarContainer}>
|
||||
<SpMenu
|
||||
<div
|
||||
id="menu-bar-container"
|
||||
style={{
|
||||
...styles.menuBarContainer,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{/* <SpMenu
|
||||
title="Stable Diffusion Models"
|
||||
items={helper_store.data.models.map((model) => {
|
||||
return model.model_name
|
||||
})}
|
||||
items={helper_store.data.models || []}
|
||||
label_item="Select a Model"
|
||||
style={{ ...styles.spMenu }}
|
||||
selected_index={helper_store.data.models
|
||||
.map((model) => {
|
||||
return model.title
|
||||
})
|
||||
.indexOf(store.data.selected_model)}
|
||||
selected_index={(
|
||||
helper_store.data.models || []
|
||||
).indexOf(store.data.selected_model)}
|
||||
onChange={(id: any, value: any) => {
|
||||
// console.log('onChange value: ', value)
|
||||
// store.updateProperty('subject', value.item)
|
||||
console.log('value:', value)
|
||||
store.data.selected_model = value.item
|
||||
|
||||
//REFACTOR: move to events.js
|
||||
const model_index = value.index
|
||||
let model = helper_store.data.models[model_index]
|
||||
|
||||
// g_model_name = `${model.model_name}.ckpt`
|
||||
requestSwapModel(store.data.selected_model)
|
||||
}}
|
||||
></SpMenu> */}
|
||||
<SearchableMenu
|
||||
allItems={helper_store.data.models}
|
||||
placeholder={'Select a Model'}
|
||||
selected_item={store.data.selected_model}
|
||||
onSelectItemFailure={() => {
|
||||
const default_value =
|
||||
helper_store.data.models[0] || ''
|
||||
store.data.selected_model = default_value
|
||||
return default_value
|
||||
}}
|
||||
onChange={(item: any) => {
|
||||
store.data.selected_model = item
|
||||
|
||||
requestSwapModel(store.data.selected_model)
|
||||
}}
|
||||
></SpMenu>
|
||||
/>
|
||||
|
||||
<button
|
||||
title="Refresh the plugin, only fixes minor issues."
|
||||
id="btnRefreshModels"
|
||||
style={styles.button}
|
||||
onClick={async (e) => {
|
||||
await refreshUI()
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start' }}>
|
||||
<button
|
||||
style={{ padding: '3px' }}
|
||||
title="Refresh the plugin, only fixes minor issues."
|
||||
id="btnRefreshModels"
|
||||
// style={styles.button}
|
||||
onClick={async (e) => {
|
||||
await refreshUI()
|
||||
|
||||
tempDisableElement(e.target, 3000)
|
||||
}}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
<button
|
||||
title="Update the plugin if you encounter bugs. Get the latest features"
|
||||
className="btnSquare"
|
||||
id="btnUpdate"
|
||||
style={styles.button}
|
||||
onClick={async () => {
|
||||
await updateClickEventHandler(g_version)
|
||||
}}
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
tempDisableElement(e.target, 3000)
|
||||
}}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
<button
|
||||
style={{ padding: '3px' }}
|
||||
title="Update the plugin if you encounter bugs. Get the latest features"
|
||||
className="btnSquare"
|
||||
id="btnUpdate"
|
||||
// style={styles.button}
|
||||
onClick={async () => {
|
||||
await updateClickEventHandler(g_version)
|
||||
}}
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sdBtnContainer">
|
||||
<SpMenu
|
||||
{/* <SpMenu
|
||||
title="use lora in your prompt"
|
||||
style={{ ...styles.spMenu }}
|
||||
items={helper_store.data.loras.map((lora: any) => {
|
||||
return lora.name
|
||||
})}
|
||||
// items={helper_store.data.loras.map((lora: any) => {
|
||||
// return lora.name
|
||||
// })}
|
||||
items={helper_store.data.loras}
|
||||
label_item="Select Lora"
|
||||
// selected_index={store.data.models
|
||||
// .map((model) => {
|
||||
|
|
@ -272,8 +313,19 @@ class SDTab extends React.Component<{}> {
|
|||
positive: `${prompt} ${lora_prompt}`,
|
||||
})
|
||||
}}
|
||||
></SpMenu>
|
||||
<SpMenu
|
||||
></SpMenu> */}
|
||||
<SearchableMenu
|
||||
allItems={helper_store.data.loras}
|
||||
placeholder={'Select Lora'}
|
||||
onChange={(item: any) => {
|
||||
const lora_prompt = getLoraModelPrompt(item)
|
||||
const prompt = multiPrompts.getPrompt().positive
|
||||
multiPrompts.setPrompt({
|
||||
positive: `${prompt} ${lora_prompt}`,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
{/* <SpMenu
|
||||
title="use textual inversion in your prompt"
|
||||
style={{ ...styles.spMenu }}
|
||||
items={helper_store.data.embeddings}
|
||||
|
|
@ -284,7 +336,17 @@ class SDTab extends React.Component<{}> {
|
|||
positive: `${prompt} ${value.item}`,
|
||||
})
|
||||
}}
|
||||
></SpMenu>
|
||||
></SpMenu> */}
|
||||
<SearchableMenu
|
||||
allItems={helper_store.data.embeddings || []}
|
||||
placeholder={Locale('Select Textual Inversion')}
|
||||
onChange={(item: any) => {
|
||||
const prompt = multiPrompts.getPrompt().positive
|
||||
multiPrompts.setPrompt({
|
||||
positive: `${prompt} ${item}`,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
<sp-checkbox
|
||||
title="use {keyword} form the prompts library"
|
||||
|
|
@ -341,7 +403,10 @@ class SDTab extends React.Component<{}> {
|
|||
padding: '3px',
|
||||
}}
|
||||
>
|
||||
<Collapsible defaultIsOpen={true} label={'Prompts'}>
|
||||
<Collapsible
|
||||
defaultIsOpen={true}
|
||||
label={Locale('Prompts')}
|
||||
>
|
||||
<MultiTextArea />
|
||||
</Collapsible>
|
||||
</div>
|
||||
|
|
@ -363,7 +428,7 @@ class SDTab extends React.Component<{}> {
|
|||
: void 0
|
||||
}
|
||||
>
|
||||
{config.name}
|
||||
{Locale(config.name)}
|
||||
</sp-radio>
|
||||
)
|
||||
})}
|
||||
|
|
@ -465,7 +530,7 @@ class SDTab extends React.Component<{}> {
|
|||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<sp-label>Batch Size:</sp-label>
|
||||
<sp-label>{Locale('Batch Size:')}</sp-label>
|
||||
<SpTextfield
|
||||
style={{ width: '100%' }}
|
||||
title="the number of images to generate at once.The larger the number more VRAM stable diffusion will use."
|
||||
|
|
@ -491,7 +556,7 @@ class SDTab extends React.Component<{}> {
|
|||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<sp-label>Batch Count:</sp-label>
|
||||
<sp-label>{Locale('Batch Count:')}</sp-label>
|
||||
<SpTextfield
|
||||
style={{ width: '100%' }}
|
||||
title="the number of images to generate in queue. The larger the number the longer will take."
|
||||
|
|
@ -515,7 +580,7 @@ class SDTab extends React.Component<{}> {
|
|||
}}
|
||||
>
|
||||
<sp-label id="sdLabelSampleStep">
|
||||
Sampling Steps
|
||||
{Locale('Sampling Steps:')}
|
||||
</sp-label>
|
||||
<SpTextfield
|
||||
style={{ width: '100%' }}
|
||||
|
|
@ -535,7 +600,7 @@ class SDTab extends React.Component<{}> {
|
|||
<div id="selectionMode">
|
||||
<div>
|
||||
<sp-label id="rbSelectionModeLabel" slot="label">
|
||||
Selection Mode:
|
||||
{Locale('Selection Mode:')}
|
||||
</sp-label>
|
||||
</div>
|
||||
|
||||
|
|
@ -575,7 +640,7 @@ class SDTab extends React.Component<{}> {
|
|||
}
|
||||
}}
|
||||
>
|
||||
{selection_mode.name}
|
||||
{Locale(selection_mode.name)}
|
||||
</sp-radio>
|
||||
)
|
||||
}
|
||||
|
|
@ -705,7 +770,7 @@ class SDTab extends React.Component<{}> {
|
|||
}}
|
||||
>
|
||||
<sp-label slot="label" class="title">
|
||||
Width:
|
||||
{Locale('Width:')}
|
||||
</sp-label>
|
||||
<sp-label
|
||||
class="labelNumber"
|
||||
|
|
@ -746,7 +811,7 @@ class SDTab extends React.Component<{}> {
|
|||
}}
|
||||
>
|
||||
<sp-label slot="label" class="title">
|
||||
Height:
|
||||
{Locale('Height:')}
|
||||
</sp-label>
|
||||
<sp-label
|
||||
class="labelNumber"
|
||||
|
|
@ -789,7 +854,7 @@ class SDTab extends React.Component<{}> {
|
|||
}}
|
||||
>
|
||||
<sp-label slot="label" class="title">
|
||||
CFG Scale:
|
||||
{Locale('CFG Scale:')}
|
||||
</sp-label>
|
||||
</SpSlider>
|
||||
|
||||
|
|
@ -814,7 +879,7 @@ class SDTab extends React.Component<{}> {
|
|||
}}
|
||||
>
|
||||
<sp-label slot="label" class="title">
|
||||
Denoising Strength:
|
||||
{Locale('Denoising Strength:')}
|
||||
</sp-label>
|
||||
<sp-label slot="label" id="lDenoisingStrength">
|
||||
{store.data.denoising_strength.toFixed(2)}
|
||||
|
|
@ -933,7 +998,9 @@ class SDTab extends React.Component<{}> {
|
|||
}
|
||||
}}
|
||||
>
|
||||
<sp-label slot="label">Mask Expansion:</sp-label>
|
||||
<sp-label slot="label">
|
||||
{Locale('Mask Expansion:')}
|
||||
</sp-label>
|
||||
</SpSlider>
|
||||
|
||||
<div style={{ display: 'flex' }}>
|
||||
|
|
@ -997,30 +1064,31 @@ class SDTab extends React.Component<{}> {
|
|||
<sp-label class="title" slot="label">
|
||||
Mask Content:
|
||||
</sp-label>
|
||||
{mask_content_config.map(
|
||||
(mask_content, index: number) => {
|
||||
return (
|
||||
<sp-radio
|
||||
key={index}
|
||||
class="rbMaskContent"
|
||||
checked={
|
||||
store.data
|
||||
.inpainting_fill ===
|
||||
{(settings_tab_ts.store.data
|
||||
.selected_backend === 'Automatic1111'
|
||||
? mask_content_config
|
||||
: comfy_mask_content_config
|
||||
).map((mask_content, index: number) => {
|
||||
return (
|
||||
<sp-radio
|
||||
key={index}
|
||||
class="rbMaskContent"
|
||||
checked={
|
||||
store.data.inpainting_fill ===
|
||||
mask_content.value
|
||||
? true
|
||||
: void 0
|
||||
}
|
||||
value={mask_content.value}
|
||||
onClick={(evt: any) => {
|
||||
store.data.inpainting_fill =
|
||||
mask_content.value
|
||||
? true
|
||||
: void 0
|
||||
}
|
||||
value={mask_content.value}
|
||||
onClick={(evt: any) => {
|
||||
store.data.inpainting_fill =
|
||||
mask_content.value
|
||||
}}
|
||||
>
|
||||
{mask_content.name}
|
||||
</sp-radio>
|
||||
)
|
||||
}
|
||||
)}
|
||||
}}
|
||||
>
|
||||
{Locale(`${mask_content.name}`)}
|
||||
</sp-radio>
|
||||
)
|
||||
})}
|
||||
</sp-radio-group>
|
||||
</div>
|
||||
|
||||
|
|
@ -1053,24 +1121,20 @@ class SDTab extends React.Component<{}> {
|
|||
evt.target.checked
|
||||
}}
|
||||
>
|
||||
Restore Faces
|
||||
{Locale('Restore Faces')}
|
||||
</SpCheckBox>
|
||||
<SpCheckBox
|
||||
class="checkbox"
|
||||
id="chHiResFixs"
|
||||
style={{
|
||||
display: [ScriptMode.Txt2Img].includes(
|
||||
store.data.rb_mode
|
||||
)
|
||||
? 'flex'
|
||||
: 'none',
|
||||
display: isHiResMode() ? 'flex' : 'none',
|
||||
}}
|
||||
checked={store.data.enable_hr}
|
||||
onClick={(evt: any) => {
|
||||
store.data.enable_hr = evt.target.checked
|
||||
}}
|
||||
>
|
||||
Hi Res Fix
|
||||
{Locale('Hi Res Fix')}
|
||||
</SpCheckBox>
|
||||
<SpCheckBox
|
||||
class="checkbox"
|
||||
|
|
@ -1080,16 +1144,14 @@ class SDTab extends React.Component<{}> {
|
|||
store.data.tiling = evt.target.checked
|
||||
}}
|
||||
>
|
||||
tiling
|
||||
{Locale('Tiling')}
|
||||
</SpCheckBox>
|
||||
</div>
|
||||
<div
|
||||
id="HiResDiv"
|
||||
style={{
|
||||
display:
|
||||
[ScriptMode.Txt2Img].includes(
|
||||
store.data.rb_mode
|
||||
) && store.data.enable_hr
|
||||
isHiResMode() && store.data.enable_hr
|
||||
? void 0
|
||||
: 'none',
|
||||
}}
|
||||
|
|
@ -1304,7 +1366,9 @@ class SDTab extends React.Component<{}> {
|
|||
|
||||
<div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<sp-label id="sdLabelSeed">Seed:</sp-label>
|
||||
<sp-label id="sdLabelSeed">
|
||||
{Locale('Seed:')}
|
||||
</sp-label>
|
||||
<sp-textfield
|
||||
id="tiSeed"
|
||||
placeholder="Seed"
|
||||
|
|
@ -1324,7 +1388,7 @@ class SDTab extends React.Component<{}> {
|
|||
store.data.seed = '-1'
|
||||
}}
|
||||
>
|
||||
Random
|
||||
{Locale('Random')}
|
||||
</button>
|
||||
<button
|
||||
className="btnSquare"
|
||||
|
|
@ -1334,7 +1398,7 @@ class SDTab extends React.Component<{}> {
|
|||
session_store.data.last_seed
|
||||
}}
|
||||
>
|
||||
Last
|
||||
{Locale('Last')}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
|
|
@ -1358,26 +1422,28 @@ class SDTab extends React.Component<{}> {
|
|||
: 'none',
|
||||
}}
|
||||
>
|
||||
<sp-label slot="label">Select Sampler:</sp-label>
|
||||
{helper_store.data.sampler_list.map(
|
||||
<sp-label slot="label">
|
||||
{Locale('Select Sampler:')}
|
||||
</sp-label>
|
||||
{(helper_store.data.sampler_list || []).map(
|
||||
(sampler: any, index: number) => {
|
||||
return (
|
||||
<sp-radio
|
||||
class="rbSampler"
|
||||
checked={
|
||||
sampler.name ===
|
||||
sampler ===
|
||||
store.data.sampler_name
|
||||
? true
|
||||
: void 0
|
||||
}
|
||||
value={sampler.name}
|
||||
value={sampler}
|
||||
key={index}
|
||||
onClick={(evt: any) => {
|
||||
store.data.sampler_name =
|
||||
sampler.name
|
||||
sampler
|
||||
}}
|
||||
>
|
||||
{sampler.name}
|
||||
{sampler}
|
||||
</sp-radio>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { control_net, main } from '../entry'
|
||||
import { control_net } from '../entry'
|
||||
import vae_settings from '../settings/vae'
|
||||
import { AStore } from '../main/astore'
|
||||
import { script_store } from '../ultimate_sd_upscaler/scripts'
|
||||
import { ScriptMode } from '../ultimate_sd_upscaler/ultimate_sd_upscaler'
|
||||
|
|
@ -28,7 +29,7 @@ import { presetToStore } from '../util/ts/io'
|
|||
import { refreshExtraUpscalers } from '../extra_page/extra_page'
|
||||
|
||||
import { readdirSync, readFileSync } from 'fs'
|
||||
|
||||
import comfyapi from '../comfyui/comfyapi'
|
||||
declare let g_models: any[]
|
||||
declare let g_automatic_status: any
|
||||
declare let g_sd_options_obj: any
|
||||
|
|
@ -76,6 +77,24 @@ export const mask_content_config = [
|
|||
value: 3,
|
||||
},
|
||||
]
|
||||
export const comfy_mask_content_config = [
|
||||
// {
|
||||
// name: 'fill',
|
||||
// value: 0,
|
||||
// },
|
||||
{
|
||||
name: 'original',
|
||||
value: 1,
|
||||
},
|
||||
// {
|
||||
// name: 'latent noise',
|
||||
// value: 2,
|
||||
// },
|
||||
{
|
||||
name: 'latent nothing',
|
||||
value: 3,
|
||||
},
|
||||
]
|
||||
export enum SelectionModeEnum {
|
||||
Ratio = 'ratio',
|
||||
Precise = 'precise',
|
||||
|
|
@ -114,7 +133,7 @@ export const store = new AStore({
|
|||
cfg: 7.0,
|
||||
b_width_height_link: true,
|
||||
denoising_strength: 0.7,
|
||||
hr_denoising_strength: 0.7,
|
||||
hr_denoising_strength: 0.5,
|
||||
inpaint_full_res: false,
|
||||
enable_hr: false,
|
||||
sampler_name: 'Euler a',
|
||||
|
|
@ -128,9 +147,11 @@ export const store = new AStore({
|
|||
|
||||
hr_resize_x: 512,
|
||||
hr_resize_y: 512,
|
||||
hr_second_pass_steps: 0,
|
||||
hr_second_pass_steps: 20,
|
||||
restore_faces: false,
|
||||
inpainting_fill: mask_content_config[0].value,
|
||||
// inpainting_fill: mask_content_config[0].value,
|
||||
inpainting_fill: 1, //set original as default value
|
||||
|
||||
hr_upscaler: '',
|
||||
|
||||
selection_mode: selection_mode_config[0].value,
|
||||
|
|
@ -166,7 +187,7 @@ export const default_preset = {
|
|||
hr_resize_y: 512,
|
||||
hr_second_pass_steps: 0,
|
||||
// restore_faces: false,
|
||||
inpainting_fill: 0,
|
||||
inpainting_fill: 1,
|
||||
hr_upscaler: '',
|
||||
selection_mode: 'ratio',
|
||||
},
|
||||
|
|
@ -185,6 +206,7 @@ export const helper_store = new AStore({
|
|||
native_presets: {},
|
||||
base_size: 512 as number,
|
||||
lasso_offset: 10 as number,
|
||||
make_square: true as boolean,
|
||||
})
|
||||
export async function refreshModels() {
|
||||
let b_result = false
|
||||
|
|
@ -192,10 +214,13 @@ export async function refreshModels() {
|
|||
g_models = await requestGetModels()
|
||||
if (g_models.length > 0) {
|
||||
b_result = true
|
||||
helper_store.data.models = g_models
|
||||
? g_models.map((model) => {
|
||||
return model.title
|
||||
})
|
||||
: helper_store.data.models
|
||||
}
|
||||
|
||||
helper_store.data.models = g_models
|
||||
|
||||
// for (let model of g_models) {
|
||||
// // console.log(model.title)//Log
|
||||
// // const menu_item_element = document.createElement('sp-menu-item')
|
||||
|
|
@ -303,39 +328,19 @@ async function updateVersionUI() {
|
|||
|
||||
//REFACTOR: move to generation_settings.js
|
||||
export async function initSamplers() {
|
||||
let bStatus = false
|
||||
try {
|
||||
// let sampler_group = document.getElementById('sampler_group')!
|
||||
// sampler_group.innerHTML = ''
|
||||
|
||||
let samplers = await requestGetSamplers()
|
||||
if (!samplers) {
|
||||
//if we failed to get the sampler list from auto1111, use the list stored in sampler.js
|
||||
samplers = sampler_data.samplers
|
||||
}
|
||||
helper_store.data.sampler_list = samplers
|
||||
|
||||
// for (let sampler of samplers) {
|
||||
// // console.log(sampler)//Log
|
||||
// // sampler.name
|
||||
// // <sp-radio class="rbSampler" value="Euler">Euler</sp-radio>
|
||||
// // const rbSampler = document.createElement('sp-radio')
|
||||
// // rbSampler.innerHTML = sampler.name
|
||||
// // rbSampler.setAttribute('class', 'rbSampler')
|
||||
// // rbSampler.setAttribute('value', sampler.name)
|
||||
// // sampler_group.appendChild(rbSampler)
|
||||
// //add click event on radio button for Sampler radio button, so that when a button is clicked it change g_sd_sampler globally
|
||||
// }
|
||||
// document
|
||||
// .getElementsByClassName('rbSampler')[0]
|
||||
// .setAttribute('checked', '')
|
||||
if (samplers.length > 0) {
|
||||
bStatus = true
|
||||
helper_store.data.sampler_list = samplers.map((sampler: any) => {
|
||||
return sampler.name
|
||||
})
|
||||
store.data.sampler_name = helper_store.data.sampler_list[0]
|
||||
}
|
||||
return samplers
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
return bStatus
|
||||
return []
|
||||
}
|
||||
|
||||
export function loadNativePreset() {
|
||||
|
|
@ -363,47 +368,88 @@ export async function refreshUI() {
|
|||
html_manip.setProxyServerStatus('disconnected', 'connected')
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
g_automatic_status = await checkAutoStatus() // check the webui status regardless if alert are turned on or off
|
||||
if (!settings_tab_ts.store.data.bTurnOffServerStatusAlert) {
|
||||
//@ts-ignore
|
||||
await displayNotification(g_automatic_status) // only show alert if the alert are turn on
|
||||
}
|
||||
const bSamplersStatus = await initSamplers()
|
||||
|
||||
await refreshModels()
|
||||
helper_store.data.loras = await requestLoraModels()
|
||||
helper_store.data.embeddings = await requestEmbeddings()
|
||||
await refreshExtraUpscalers()
|
||||
|
||||
await setInpaintMaskWeight(1.0) //set the inpaint conditional mask to 1 when the on plugin start
|
||||
|
||||
//get the latest options
|
||||
|
||||
await g_sd_options_obj.getOptions()
|
||||
//get the selected model
|
||||
store.data.selected_model = g_sd_options_obj.getCurrentModel()
|
||||
//update the ui with that model title
|
||||
|
||||
// const current_model_hash =
|
||||
// html_manip.getModelHashByTitle(current_model_title)
|
||||
// html_manip.autoFillInModel(current_model_hash)
|
||||
|
||||
//fetch the inpaint mask weight from sd webui and update the slider with it.
|
||||
const inpainting_mask_weight =
|
||||
await g_sd_options_obj.getInpaintingMaskWeight()
|
||||
console.log('inpainting_mask_weight: ', inpainting_mask_weight)
|
||||
html_manip.autoFillInInpaintMaskWeight(inpainting_mask_weight)
|
||||
|
||||
//init ControlNet Tab
|
||||
|
||||
helper_store.data.hr_upscaler_list = await requestGetHiResUpscalers()
|
||||
|
||||
g_controlnet_max_models = await control_net.requestControlNetMaxUnits()
|
||||
await control_net.initializeControlNetTab(g_controlnet_max_models)
|
||||
await main.populateVAE()
|
||||
|
||||
helper_store.data.native_presets = loadNativePreset()
|
||||
if (settings_tab_ts.store.data.selected_backend === 'Automatic1111') {
|
||||
//@ts-ignore
|
||||
g_automatic_status = await checkAutoStatus() // check the webui status regardless if alert are turned on or off
|
||||
if (!settings_tab_ts.store.data.bTurnOffServerStatusAlert) {
|
||||
//@ts-ignore
|
||||
await displayNotification(g_automatic_status) // only show alert if the alert are turn on
|
||||
}
|
||||
const bSamplersStatus = await initSamplers()
|
||||
await refreshModels()
|
||||
helper_store.data.loras = await requestLoraModels()
|
||||
helper_store.data.embeddings = await requestEmbeddings()
|
||||
await refreshExtraUpscalers()
|
||||
await setInpaintMaskWeight(1.0) //set the inpaint conditional mask to 1 when the on plugin start
|
||||
//get the latest options
|
||||
|
||||
await g_sd_options_obj.getOptions()
|
||||
//get the selected model
|
||||
store.data.selected_model = g_sd_options_obj.getCurrentModel()
|
||||
//update the ui with that model title
|
||||
|
||||
// const current_model_hash =
|
||||
// html_manip.getModelHashByTitle(current_model_title)
|
||||
// html_manip.autoFillInModel(current_model_hash)
|
||||
|
||||
//fetch the inpaint mask weight from sd webui and update the slider with it.
|
||||
const inpainting_mask_weight =
|
||||
await g_sd_options_obj.getInpaintingMaskWeight()
|
||||
console.log('inpainting_mask_weight: ', inpainting_mask_weight)
|
||||
html_manip.autoFillInInpaintMaskWeight(inpainting_mask_weight)
|
||||
//init ControlNet Tab
|
||||
|
||||
helper_store.data.hr_upscaler_list =
|
||||
await requestGetHiResUpscalers()
|
||||
|
||||
g_controlnet_max_models =
|
||||
await control_net.requestControlNetMaxUnits()
|
||||
await control_net.initializeControlNetTab(g_controlnet_max_models)
|
||||
await vae_settings.populateVAE()
|
||||
}
|
||||
|
||||
if (settings_tab_ts.store.data.selected_backend === 'ComfyUI') {
|
||||
await comfyapi.comfy_api.init()
|
||||
|
||||
helper_store.data.models = comfyapi.comfy_api.getModels()
|
||||
store.data.selected_model = helper_store.data.models?.[0]
|
||||
|
||||
helper_store.data.sampler_list =
|
||||
comfyapi.comfy_api.getSamplerNames()
|
||||
store.data.sampler_name = helper_store.data.sampler_list?.[0]
|
||||
|
||||
vae_settings.store.data.vae_model_list =
|
||||
comfyapi.comfy_api.getVAEs()
|
||||
vae_settings.store.data.current_vae =
|
||||
vae_settings.store.data.vae_model_list?.[0]
|
||||
|
||||
helper_store.data.hr_upscaler_list =
|
||||
comfyapi.comfy_api.getHiResUpscalers()
|
||||
store.data.hr_upscaler = helper_store.data.hr_upscaler_list?.[0]
|
||||
|
||||
helper_store.data.loras = comfyapi.comfy_api
|
||||
.getLoras()
|
||||
.map((lora) => lora.split('.')[0]) //remove .safetensor from loraname
|
||||
|
||||
const controlnet_models =
|
||||
//@ts-ignorets
|
||||
comfyapi.comfy_api.object_info?.ControlNetLoader.input.required
|
||||
.control_net_name[0]
|
||||
const preprocessor_list = //@ts-ignorets
|
||||
comfyapi.comfy_api?.object_info?.ControlNetScript.input.required
|
||||
.preprocessor_name_1[0]
|
||||
const preprocessor_detail =
|
||||
//@ts-ignorets
|
||||
comfyapi.comfy_api?.object_info?.GetConfig.input.optional
|
||||
.controlnet_config
|
||||
control_net.initializeControlNetTabComfyUI(
|
||||
3,
|
||||
controlnet_models,
|
||||
preprocessor_list,
|
||||
preprocessor_detail
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
|
|
@ -437,7 +483,12 @@ export async function requestGetHiResUpscalers(): Promise<string[]> {
|
|||
|
||||
export async function requestLoraModels() {
|
||||
const full_url = `${g_sd_url}/sdapi/v1/loras`
|
||||
const lora_models = (await requestGet(full_url)) ?? []
|
||||
let lora_models = (await requestGet(full_url)) ?? []
|
||||
if (lora_models.length > 0) {
|
||||
lora_models = lora_models.map((lora: any) => {
|
||||
return lora.name
|
||||
})
|
||||
}
|
||||
return lora_models
|
||||
}
|
||||
|
||||
|
|
@ -688,6 +739,20 @@ export function loadPresetSettings(preset: any) {
|
|||
// io_ts.presetToStore(preset?.controlnet_tab_preset, store)
|
||||
}
|
||||
}
|
||||
export function isHiResMode() {
|
||||
let is_hi_res_mode = false
|
||||
if (settings_tab_ts.store.data.selected_backend === 'Automatic1111') {
|
||||
is_hi_res_mode = [ScriptMode.Txt2Img].includes(store.data.rb_mode)
|
||||
} else if (settings_tab_ts.store.data.selected_backend === 'ComfyUI') {
|
||||
is_hi_res_mode = [
|
||||
ScriptMode.Txt2Img,
|
||||
ScriptMode.Img2Img,
|
||||
ScriptMode.Inpaint,
|
||||
ScriptMode.Outpaint,
|
||||
].includes(store.data.rb_mode)
|
||||
}
|
||||
return is_hi_res_mode
|
||||
}
|
||||
|
||||
export default {
|
||||
store: store,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
mask_store as viewer_mask_store,
|
||||
// init_store as viewer_init_store,
|
||||
} from '../viewer/viewer_util'
|
||||
import { settings_tab_ts } from '../entry'
|
||||
|
||||
declare let g_automatic_status: any
|
||||
declare let g_current_batch_index: number
|
||||
|
|
@ -44,7 +45,7 @@ export const GenerateButtons = observer(() => {
|
|||
display: session_store.data.can_generate ? void 0 : 'none',
|
||||
}}
|
||||
>
|
||||
Generate {modeDisplayNames[sd_tab_store.data.mode]}
|
||||
{Locale(`Generate ${modeDisplayNames[sd_tab_store.data.mode]}`)}
|
||||
</button>
|
||||
{session_store.data.can_generate ? (
|
||||
<button
|
||||
|
|
@ -161,10 +162,13 @@ const canStartSession = async () => {
|
|||
await psapi.reSelectMarqueeExe(session_store.data.selectionInfo)
|
||||
}
|
||||
}
|
||||
//@ts-ignore
|
||||
g_automatic_status = await checkAutoStatus()
|
||||
//@ts-ignore
|
||||
await displayNotification(g_automatic_status)
|
||||
|
||||
if (settings_tab_ts.store.data.selected_backend === 'Automatic1111') {
|
||||
//@ts-ignore
|
||||
g_automatic_status = await checkAutoStatus()
|
||||
//@ts-ignore
|
||||
await displayNotification(g_automatic_status)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
|
|
@ -226,6 +230,7 @@ const handleGenerate = async () => {
|
|||
console.error(e)
|
||||
console.warn('output_images: ', output_images)
|
||||
console.warn('response_json: ', response_json)
|
||||
console.warn('ui_settings: ', ui_settings)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import * as scripts from '../ultimate_sd_upscaler/scripts'
|
|||
import * as control_net from '../controlnet/entry'
|
||||
import { store as session_store } from '../session/session_store'
|
||||
import sd_tab_util from '../sd_tab/util'
|
||||
|
||||
import settings_tab from '../settings/settings'
|
||||
import comfyui_main_ui from '../comfyui/main_ui'
|
||||
import {
|
||||
html_manip,
|
||||
io,
|
||||
|
|
@ -23,6 +24,9 @@ import {
|
|||
} from '../controlnet/entry'
|
||||
|
||||
import { store as extra_page_store } from '../extra_page/extra_page'
|
||||
import { requestPost } from '../util/ts/api'
|
||||
import { comfyapi, settings_tab_ts } from '../entry'
|
||||
import { newOutputImageName } from '../util/ts/general'
|
||||
const executeAsModal = core.executeAsModal
|
||||
|
||||
declare let g_inpaint_mask_layer: any
|
||||
|
|
@ -35,9 +39,17 @@ interface SessionData {
|
|||
mask?: string
|
||||
selectionInfo?: any
|
||||
}
|
||||
interface ImageInfo {
|
||||
path: string
|
||||
base64: string
|
||||
auto_metadata: Record<string, any>
|
||||
}
|
||||
|
||||
async function saveOutputImagesToDrive(images_info: any, settings: any) {
|
||||
const base64OutputImages = [] //delete all previouse images, Note move this to session end ()
|
||||
async function saveOutputImagesToDrive(
|
||||
images_info: ImageInfo[],
|
||||
settings: Record<string, any>
|
||||
) {
|
||||
const base64OutputImages = []
|
||||
let index = 0
|
||||
for (const image_info of images_info) {
|
||||
const path = image_info['path']
|
||||
|
|
@ -55,10 +67,32 @@ async function saveOutputImagesToDrive(images_info: any, settings: any) {
|
|||
) //save the settings
|
||||
index += 1
|
||||
}
|
||||
session_store.data.last_seed =
|
||||
images_info?.length > 0 ? images_info[0]?.auto_metadata?.Seed : '-1'
|
||||
if (settings_tab_ts.store.data.selected_backend === 'Automatic1111') {
|
||||
session_store.data.last_seed =
|
||||
images_info?.length > 0 ? images_info[0]?.auto_metadata?.Seed : '-1'
|
||||
}
|
||||
return base64OutputImages
|
||||
}
|
||||
async function saveOutputImagesToDriveComfy(
|
||||
base64_images: string[],
|
||||
settings: Record<string, any>
|
||||
) {
|
||||
let index = 0
|
||||
const document_name = settings['uniqueDocumentId']
|
||||
delete settings['alwayson_scripts']
|
||||
for (const base64 of base64_images) {
|
||||
const image_name = newOutputImageName()
|
||||
await io.saveFileInSubFolder(base64, document_name, image_name) //save the output image
|
||||
const json_file_name = `${image_name.split('.')[0]}.json`
|
||||
|
||||
await io.saveJsonFileInSubFolder(
|
||||
settings,
|
||||
document_name,
|
||||
json_file_name
|
||||
) //save the settings
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
class Mode {
|
||||
constructor() {}
|
||||
|
||||
|
|
@ -86,7 +120,13 @@ class Mode {
|
|||
return base64OutputImages
|
||||
}
|
||||
static async interrupt() {
|
||||
return await this.requestInterrupt()
|
||||
//automatic1111
|
||||
if (settings_tab.store.data.selected_backend === 'Automatic1111') {
|
||||
return await this.requestInterrupt()
|
||||
} else if (settings_tab.store.data.selected_backend === 'ComfyUI') {
|
||||
await comfyapi.comfy_api.interrupt()
|
||||
//comfy
|
||||
}
|
||||
}
|
||||
|
||||
static async requestInterrupt() {
|
||||
|
|
@ -150,8 +190,9 @@ export class Txt2ImgMode extends Mode {
|
|||
|
||||
const full_url = `${g_sd_url}/sdapi/v1/txt2img`
|
||||
|
||||
const control_net_settings =
|
||||
mapPluginSettingsToControlNet(plugin_settings)
|
||||
const control_net_settings = await mapPluginSettingsToControlNet(
|
||||
plugin_settings
|
||||
)
|
||||
let control_networks = []
|
||||
// let active_control_networks = 0
|
||||
for (let index = 0; index < g_controlnet_max_models; index++) {
|
||||
|
|
@ -161,8 +202,15 @@ export class Txt2ImgMode extends Mode {
|
|||
}
|
||||
control_networks[index] = true
|
||||
|
||||
const is_inpaint_model: boolean =
|
||||
control_net_settings['controlnet_units'][index][
|
||||
'module'
|
||||
].includes('inpaint')
|
||||
if (
|
||||
!control_net_settings['controlnet_units'][index]['input_image']
|
||||
!control_net_settings['controlnet_units'][index][
|
||||
'input_image'
|
||||
] &&
|
||||
!is_inpaint_model
|
||||
) {
|
||||
//@ts-ignore
|
||||
app.showAlert('you need to add a valid ControlNet input image')
|
||||
|
|
@ -248,26 +296,39 @@ export class Txt2ImgMode extends Mode {
|
|||
// const b_enable_control_net = control_net.getEnableControlNet()
|
||||
const b_enable_control_net = control_net.isControlNetModeEnable()
|
||||
|
||||
if (b_enable_control_net) {
|
||||
//use control net
|
||||
if (session_store.data.generation_number === 1) {
|
||||
session_store.data.controlnet_input_image =
|
||||
await io.getImg2ImgInitImage()
|
||||
if (settings_tab.store.data.selected_backend === 'Automatic1111') {
|
||||
if (b_enable_control_net) {
|
||||
//use control net
|
||||
if (session_store.data.generation_number === 1) {
|
||||
session_store.data.controlnet_input_image =
|
||||
await io.getImg2ImgInitImage()
|
||||
}
|
||||
// console.log(
|
||||
// 'session_store.data.controlnet_input_image: ',
|
||||
// session_store.data.controlnet_input_image
|
||||
// )
|
||||
|
||||
response_json = await this.requestControlNetTxt2Img(
|
||||
settings
|
||||
)
|
||||
} else {
|
||||
response_json = await this.requestTxt2Img(settings) //this is automatic1111 txt2img
|
||||
}
|
||||
// console.log(
|
||||
// 'session_store.data.controlnet_input_image: ',
|
||||
// session_store.data.controlnet_input_image
|
||||
// )
|
||||
|
||||
response_json = await this.requestControlNetTxt2Img(settings)
|
||||
} else {
|
||||
response_json = await this.requestTxt2Img(settings)
|
||||
output_images = await this.processOutput(
|
||||
response_json.images_info,
|
||||
settings
|
||||
)
|
||||
} else if (settings_tab.store.data.selected_backend === 'ComfyUI') {
|
||||
//request Txt2Img from comfyui
|
||||
settings = await mapPluginSettingsToControlNet(settings)
|
||||
const { image_base64_list, image_url_list } =
|
||||
await comfyui_main_ui.generateComfyTxt2Img(settings)
|
||||
output_images = image_base64_list
|
||||
if (output_images) {
|
||||
saveOutputImagesToDriveComfy(output_images, settings)
|
||||
}
|
||||
}
|
||||
|
||||
output_images = await this.processOutput(
|
||||
response_json.images_info,
|
||||
settings
|
||||
)
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
console.warn('output_images: ', output_images)
|
||||
|
|
@ -293,8 +354,9 @@ export class Img2ImgMode extends Mode {
|
|||
//REFACTOR: reuse the same code for (requestControlNetTxt2Img,requestControlNetImg2Img)
|
||||
static async requestControlNetImg2Img(plugin_settings: any) {
|
||||
const full_url = `${g_sd_url}/sdapi/v1/img2img`
|
||||
const control_net_settings =
|
||||
mapPluginSettingsToControlNet(plugin_settings)
|
||||
const control_net_settings = await mapPluginSettingsToControlNet(
|
||||
plugin_settings
|
||||
)
|
||||
|
||||
// let control_networks = 0
|
||||
let control_networks = []
|
||||
|
|
@ -304,8 +366,17 @@ export class Img2ImgMode extends Mode {
|
|||
continue
|
||||
}
|
||||
control_networks[index] = true
|
||||
|
||||
const is_inpaint_model: boolean =
|
||||
control_net_settings['controlnet_units'][index][
|
||||
'module'
|
||||
].includes('inpaint')
|
||||
|
||||
if (
|
||||
!control_net_settings['controlnet_units'][index]['input_image']
|
||||
!control_net_settings['controlnet_units'][index][
|
||||
'input_image'
|
||||
] &&
|
||||
!is_inpaint_model
|
||||
) {
|
||||
//@ts-ignore
|
||||
app.showAlert('you need to add a valid ControlNet input image')
|
||||
|
|
@ -419,18 +490,42 @@ export class Img2ImgMode extends Mode {
|
|||
let output_images
|
||||
try {
|
||||
//checks on index 0 as if not enabled ignores the rest
|
||||
const b_enable_control_net = control_net.isControlNetModeEnable()
|
||||
|
||||
if (b_enable_control_net) {
|
||||
//use control net
|
||||
response_json = await this.requestControlNetImg2Img(settings)
|
||||
} else {
|
||||
response_json = await this.requestImg2Img(settings)
|
||||
if (settings_tab.store.data.selected_backend === 'Automatic1111') {
|
||||
const b_enable_control_net =
|
||||
control_net.isControlNetModeEnable()
|
||||
if (b_enable_control_net) {
|
||||
//use control net
|
||||
response_json = await this.requestControlNetImg2Img(
|
||||
settings
|
||||
)
|
||||
} else {
|
||||
response_json = await this.requestImg2Img(settings)
|
||||
}
|
||||
output_images = await this.processOutput(
|
||||
response_json.images_info,
|
||||
settings
|
||||
)
|
||||
} else if (settings_tab.store.data.selected_backend === 'ComfyUI') {
|
||||
settings = await mapPluginSettingsToControlNet(settings)
|
||||
if (settings?.mode === 'img2img') {
|
||||
const { image_base64_list, image_url_list } =
|
||||
await comfyui_main_ui.generateComfyImg2Img(settings)
|
||||
output_images = image_base64_list
|
||||
} else if (settings?.mode === 'inpaint') {
|
||||
const { image_base64_list, image_url_list } =
|
||||
await comfyui_main_ui.generateComfyInpaint(settings)
|
||||
output_images = image_base64_list
|
||||
} else if (settings?.mode === 'outpaint') {
|
||||
const { image_base64_list, image_url_list } =
|
||||
await comfyui_main_ui.generateComfyInpaint(settings)
|
||||
output_images = image_base64_list
|
||||
}
|
||||
|
||||
if (output_images) {
|
||||
saveOutputImagesToDriveComfy(output_images, settings)
|
||||
}
|
||||
}
|
||||
output_images = await this.processOutput(
|
||||
response_json.images_info,
|
||||
settings
|
||||
)
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
console.warn('output_images: ', output_images)
|
||||
|
|
@ -494,7 +589,8 @@ export class LassoInpaintMode extends Img2ImgMode {
|
|||
}
|
||||
const [init_image, mask] = await selection.inpaintLassoInitImageAndMask(
|
||||
'mask',
|
||||
sd_tab_util.helper_store.data.lasso_offset
|
||||
sd_tab_util.helper_store.data.lasso_offset,
|
||||
sd_tab_util.helper_store.data.make_square
|
||||
)
|
||||
|
||||
const selectionInfo = await psapi.getSelectionInfoExe()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ import {
|
|||
updateViewerStoreImageAndThumbnail,
|
||||
} from '../viewer/viewer_util'
|
||||
import { sd_tab_store } from '../stores'
|
||||
|
||||
import settings_tab from '../settings/settings'
|
||||
import comfyui_util from '../comfyui/util'
|
||||
declare let g_inpaint_mask_layer: any
|
||||
declare const g_image_not_found_url: string
|
||||
declare let g_current_batch_index: number
|
||||
|
|
@ -150,11 +151,19 @@ export async function getExpandedMask(
|
|||
//only if mask is available and sharp_mask is off
|
||||
// use blurry and expanded mask
|
||||
const iterations = expansion_value
|
||||
expanded_mask = await python_replacement.maskExpansionRequest(
|
||||
mask,
|
||||
iterations,
|
||||
blur
|
||||
)
|
||||
if (settings_tab.store.data.selected_backend === 'Automatic1111') {
|
||||
expanded_mask = await python_replacement.maskExpansionRequest(
|
||||
mask,
|
||||
iterations,
|
||||
blur
|
||||
)
|
||||
} else if (settings_tab.store.data.selected_backend === 'ComfyUI') {
|
||||
expanded_mask = await comfyui_util.maskExpansion(
|
||||
mask,
|
||||
iterations,
|
||||
blur
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// return expanded_mask
|
||||
|
|
@ -182,6 +191,7 @@ export class Session {
|
|||
store.data.current_session_id = await incrementSessionID()
|
||||
|
||||
store.data.mode = mode
|
||||
store.data.rb_mode = sd_tab_store.data.rb_mode
|
||||
|
||||
if (modeToClassMap.hasOwnProperty(store.data.mode)) {
|
||||
const { selectionInfo, init_image, mask } =
|
||||
|
|
@ -296,6 +306,7 @@ export class Session {
|
|||
selectionInfo,
|
||||
init_image,
|
||||
mask,
|
||||
rb_mode: store.data.rb_mode, // set in initializeSession
|
||||
})
|
||||
|
||||
//this should be part of initialization method or gettingSettings()
|
||||
|
|
@ -350,6 +361,7 @@ export class Session {
|
|||
init_image: store.data.init_image,
|
||||
mask: store.data.preprocessed_mask,
|
||||
selectionInfo: store.data.selectionInfo,
|
||||
rb_mode: store.data.rb_mode, // set in initializeSession
|
||||
}
|
||||
var ui_settings = await this.getSettings(session_data)
|
||||
if (
|
||||
|
|
@ -395,7 +407,11 @@ export class Session {
|
|||
}
|
||||
static async getProgress() {
|
||||
// Progress.startSudoProgress()
|
||||
progress.Progress.startTimer(async () => {
|
||||
|
||||
const comfyProgress = async () => {
|
||||
progress.store.data.progress_value += 1
|
||||
}
|
||||
const auto1111Progress = async () => {
|
||||
try {
|
||||
let json = await progress.requestProgress()
|
||||
const can_update = progress.store.data.can_update
|
||||
|
|
@ -422,7 +438,12 @@ export class Session {
|
|||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
const [callback, timer] =
|
||||
settings_tab.store.data.selected_backend === 'Automatic1111'
|
||||
? [auto1111Progress, 2000]
|
||||
: [comfyProgress, 1000]
|
||||
progress.Progress.startTimer(callback, timer)
|
||||
}
|
||||
static async endProgress() {
|
||||
await progress.Progress.endTimer(async () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { AStore } from '../main/astore'
|
||||
import { GenerationModeEnum, SelectionInfoType } from '../util/ts/enum'
|
||||
import {
|
||||
GenerationModeEnum,
|
||||
ScriptMode,
|
||||
SelectionInfoType,
|
||||
} from '../util/ts/enum'
|
||||
|
||||
interface AStoreUISettings {
|
||||
batch_size: number
|
||||
|
|
@ -17,6 +21,7 @@ interface AStoreData {
|
|||
preprocessed_mask: string //
|
||||
sd_mask: string // mask send to sd as payload[mask]
|
||||
mode: GenerationModeEnum
|
||||
rb_mode: ScriptMode
|
||||
|
||||
ui_settings: AStoreUISettings
|
||||
selectionInfo: SelectionInfoType | undefined //the session selection info
|
||||
|
|
@ -47,6 +52,7 @@ export const store = new AStore<AStoreData>({
|
|||
preprocessed_mask: '', //
|
||||
sd_mask: '', // mask send to sd as payload[mask]
|
||||
mode: GenerationModeEnum.Txt2Img,
|
||||
rb_mode: ScriptMode.Txt2Img,
|
||||
ui_settings: { batch_size: 1 },
|
||||
selectionInfo: undefined, //the session selection info
|
||||
current_selection_info: undefined, // any new selection, could be undefined too
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client'
|
|||
import { observer } from 'mobx-react'
|
||||
import { AStore } from '../main/astore'
|
||||
|
||||
import { SpCheckBox, SpMenu, SpSlider } from '../util/elements'
|
||||
import { SpCheckBox, SpMenu, SpSlider, SpTextfield } from '../util/elements'
|
||||
import Locale from '../locale/locale'
|
||||
import globalStore from '../globalstore'
|
||||
import { io } from '../util/oldSystem'
|
||||
|
|
@ -14,6 +14,7 @@ import { ErrorBoundary } from '../util/errorBoundary'
|
|||
import { MaskModeEnum, ScriptMode } from '../util/ts/enum'
|
||||
import { store as progress_store } from '../session/progress'
|
||||
import { requestPost } from '../util/ts/api'
|
||||
import { comfyapi } from '../entry'
|
||||
|
||||
// import { Jimp } from '../util/oldSystem'
|
||||
declare const Jimp: any // make sure you import jimp before importing settings.tsx
|
||||
|
|
@ -81,6 +82,8 @@ interface AStoreData {
|
|||
bTurnOffServerStatusAlert: boolean
|
||||
CLIP_stop_at_last_layers: number
|
||||
use_smart_object: boolean
|
||||
selected_backend: 'Automatic1111' | 'ComfyUI'
|
||||
comfy_url: string
|
||||
}
|
||||
export const store = new AStore<AStoreData>({
|
||||
scale_interpolation_method: interpolationMethods.bilinear,
|
||||
|
|
@ -97,6 +100,11 @@ export const store = new AStore<AStoreData>({
|
|||
false,
|
||||
CLIP_stop_at_last_layers: 1,
|
||||
use_smart_object: true, // true to keep layer as smart objects, false to rasterize them
|
||||
// selected_backend: 'Automatic1111' as 'Automatic1111' | 'ComfyUI',
|
||||
selected_backend: (storage.localStorage.getItem('selected_backend') ||
|
||||
'ComfyUI') as 'Automatic1111' | 'ComfyUI',
|
||||
comfy_url:
|
||||
storage.localStorage.getItem('comfy_url') || 'http://127.0.0.1:8188',
|
||||
})
|
||||
|
||||
function onShouldLogToFileChange(event: any) {
|
||||
|
|
@ -163,16 +171,66 @@ async function getOptions(): Promise<Options | null> {
|
|||
@observer
|
||||
export class Settings extends React.Component<{}> {
|
||||
async componentDidMount(): Promise<void> {
|
||||
const options = await getOptions()
|
||||
if (store.data.selected_backend === 'Automatic1111') {
|
||||
const options = await getOptions()
|
||||
|
||||
store.data.CLIP_stop_at_last_layers =
|
||||
options?.CLIP_stop_at_last_layers ??
|
||||
store.data.CLIP_stop_at_last_layers
|
||||
store.data.CLIP_stop_at_last_layers =
|
||||
options?.CLIP_stop_at_last_layers ??
|
||||
store.data.CLIP_stop_at_last_layers
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<sp-label>ComfyUI Url:</sp-label>
|
||||
<SpTextfield
|
||||
type="text"
|
||||
placeholder="http://127.0.0.1:8188"
|
||||
// value={config.default}
|
||||
value={store.data.comfy_url}
|
||||
onChange={(event: any) => {
|
||||
// store.data.search_query = event.target.value
|
||||
|
||||
let url = event.target.value.trim() // remove leading and trailing white spaces
|
||||
url = url.replace(/[/\\]$/, '')
|
||||
console.log(url)
|
||||
store.data.comfy_url = url
|
||||
comfyapi.comfy_api.setUrl(store.data.comfy_url)
|
||||
storage.localStorage.setItem(
|
||||
'comfy_url',
|
||||
store.data.comfy_url
|
||||
)
|
||||
}}
|
||||
></SpTextfield>
|
||||
<sp-radio-group>
|
||||
{['Automatic1111', 'ComfyUI'].map(
|
||||
(backend: any, index: number) => {
|
||||
return (
|
||||
<sp-radio
|
||||
key={index}
|
||||
title={backend}
|
||||
value={backend}
|
||||
onClick={(evt: any) => {
|
||||
store.data.selected_backend =
|
||||
evt.target.value
|
||||
storage.localStorage.setItem(
|
||||
'selected_backend',
|
||||
store.data.selected_backend
|
||||
)
|
||||
}}
|
||||
checked={
|
||||
store.data.selected_backend === backend
|
||||
? true
|
||||
: void 0
|
||||
}
|
||||
>
|
||||
{backend}
|
||||
</sp-radio>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</sp-radio-group>
|
||||
<SpMenu
|
||||
title="select an interploation method for resizing images"
|
||||
items={Object.keys(interpolationMethods)}
|
||||
|
|
@ -197,7 +255,7 @@ export class Settings extends React.Component<{}> {
|
|||
></SpMenu>
|
||||
|
||||
<div style={{ width: '100%' }}>
|
||||
<sp-label>select language</sp-label>
|
||||
<sp-label>{Locale('select language:')}</sp-label>
|
||||
</div>
|
||||
<SpMenu
|
||||
title="select language"
|
||||
|
|
@ -222,10 +280,7 @@ export class Settings extends React.Component<{}> {
|
|||
onChange={onShouldLogToFileChange}
|
||||
checked={store.data.should_log_to_file}
|
||||
>
|
||||
{
|
||||
//@ts-ignore
|
||||
Locale('Log Errors To File')
|
||||
}
|
||||
{Locale('Log Errors To File')}
|
||||
</SpCheckBox>
|
||||
</div>
|
||||
|
||||
|
|
@ -290,7 +345,7 @@ export class Settings extends React.Component<{}> {
|
|||
}}
|
||||
style={{ display: 'inline-flex' }}
|
||||
>
|
||||
Image Cfg Scale Slider
|
||||
{Locale('Image Cfg Scale Slider')}
|
||||
</sp-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -301,12 +356,14 @@ export class Settings extends React.Component<{}> {
|
|||
store.data.use_sharp_mask = evt.target.checked
|
||||
}}
|
||||
>
|
||||
use sharp mask
|
||||
{Locale('use sharp mask')}
|
||||
</sp-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<sp-radio-group selected={store.data.extension_type}>
|
||||
<sp-label slot="label">Select Extension:</sp-label>
|
||||
<sp-label slot="label">
|
||||
{Locale('Select Extension:')}
|
||||
</sp-label>
|
||||
{[
|
||||
ExtensionTypeEnum.ProxyServer,
|
||||
ExtensionTypeEnum.Auto1111Extension,
|
||||
|
|
@ -329,7 +386,7 @@ export class Settings extends React.Component<{}> {
|
|||
evt.target.value
|
||||
}}
|
||||
>
|
||||
{config[extension_type].label}
|
||||
{Locale(config[extension_type].label)}
|
||||
</sp-radio>
|
||||
)
|
||||
})}
|
||||
|
|
@ -352,7 +409,7 @@ export class Settings extends React.Component<{}> {
|
|||
)
|
||||
}}
|
||||
>
|
||||
Turn Off Server Status Alert
|
||||
{Locale('Turn Off Server Status Alert')}
|
||||
</sp-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -394,7 +451,7 @@ export class Settings extends React.Component<{}> {
|
|||
: false
|
||||
}}
|
||||
>
|
||||
Smart Object
|
||||
{Locale('Smart Object')}
|
||||
</sp-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { observer } from 'mobx-react'
|
||||
import { AStore } from './astore'
|
||||
import { AStore } from '../main/astore'
|
||||
import { SpMenu } from '../util/elements'
|
||||
|
||||
import { api, python_replacement } from '../util/oldSystem'
|
||||
|
|
@ -10,27 +10,11 @@ import '../locale/locale-for-old-html'
|
|||
import { ErrorBoundary } from '../util/errorBoundary'
|
||||
|
||||
declare let g_sd_url: string
|
||||
// class SDStore extends AStore {
|
||||
// constructor(data: any) {
|
||||
// super(data)
|
||||
// }
|
||||
// }
|
||||
|
||||
// const configValues = Object.entries(ui_config).reduce(
|
||||
// (acc, [key, value]) => ({ ...acc, [key]: value.value }),
|
||||
// {}
|
||||
// )
|
||||
// const default_values: any = {
|
||||
// _: '',
|
||||
// ...configValues,
|
||||
// }
|
||||
|
||||
const default_values: any = {
|
||||
vae_model_list: [],
|
||||
current_vae: '',
|
||||
}
|
||||
|
||||
export const store = new AStore(default_values)
|
||||
export const store = new AStore({
|
||||
vae_model_list: [] as string[],
|
||||
current_vae: '' as string,
|
||||
})
|
||||
|
||||
@observer
|
||||
export class VAEComponent extends React.Component<{
|
||||
|
|
@ -54,7 +38,6 @@ export class VAEComponent extends React.Component<{
|
|||
<SpMenu
|
||||
title="vae models"
|
||||
items={store.data.vae_model_list}
|
||||
// disabled={script_store.disabled}
|
||||
// style="width: 199px; margin-right: 5px"
|
||||
label_item="Select A VAE"
|
||||
// id={'model_list'}
|
||||
|
|
@ -111,3 +94,8 @@ vaeRoot.render(
|
|||
</ErrorBoundary>
|
||||
//</React.StrictMode>
|
||||
)
|
||||
|
||||
export default {
|
||||
store,
|
||||
populateVAE,
|
||||
}
|
||||
|
|
@ -137,8 +137,7 @@ class ToolBar extends React.Component<{}> {
|
|||
}}
|
||||
></button>
|
||||
<button
|
||||
className="btnSquare resetButton"
|
||||
id="btnResetSettings"
|
||||
className="btnSquare resetButton btnResetSettings"
|
||||
title="reset the ui settings to their default values"
|
||||
style={{ marginRight: '3px' }}
|
||||
onClick={(evt: any) => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"jsx": "react", /* Specify what JSX code is generated. */
|
||||
"experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { SpMenu } from '../util/elements'
|
|||
import * as ultimate_sd_upscale_script from './ultimate_sd_upscaler'
|
||||
import { ScriptMode } from './ultimate_sd_upscaler'
|
||||
import { ErrorBoundary } from '../util/errorBoundary'
|
||||
import Locale from '../locale/locale'
|
||||
export function toJsFunc(store: any) {
|
||||
return toJS(store)
|
||||
}
|
||||
|
|
@ -118,7 +119,7 @@ class ScriptComponent extends React.Component<{}> {
|
|||
<SpMenu
|
||||
title="Scripts"
|
||||
items={script_store.scripts_list}
|
||||
disabled={script_store.disabled}
|
||||
disabled_items={script_store.disabled}
|
||||
// style="width: 199px; margin-right: 5px"
|
||||
label_item="Select A Script"
|
||||
id={'script_list'}
|
||||
|
|
@ -139,7 +140,7 @@ class ScriptComponent extends React.Component<{}> {
|
|||
script_store.setIsActive(event.target.checked)
|
||||
}}
|
||||
>
|
||||
{'Activate'}
|
||||
{Locale('Activate')}
|
||||
</sp-checkbox>
|
||||
<>
|
||||
{script_store.selected_script_name === 'None' && <></>}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ declare global {
|
|||
'sp-textfield': any
|
||||
'sp-action-button': any
|
||||
'sp-progressbar': any
|
||||
'sp-popover': any
|
||||
'sp-dialog': any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +63,7 @@ export class SpSliderWithLabel extends React.Component<{
|
|||
output_value?: number // can be use to represent sd value
|
||||
// slider_value?: number // it's slider value can be from 1 to 100
|
||||
slider_type?: SliderType
|
||||
disabled?: boolean
|
||||
}> {
|
||||
// const [sliderValue,setSliderValue] = useState<number>(0)
|
||||
state = { output_value: this.props.output_value || 0, slider_value: 0 }
|
||||
|
|
@ -162,8 +165,7 @@ export class SpSliderWithLabel extends React.Component<{
|
|||
<div>
|
||||
<SpSlider
|
||||
show-value="false"
|
||||
// id="slControlNetWeight_0"
|
||||
class="slControlNetWeight_"
|
||||
disabled={this.props.disabled ? true : void 0}
|
||||
min={this.in_min}
|
||||
max={this.in_max}
|
||||
value={this.state.slider_value}
|
||||
|
|
@ -197,7 +199,8 @@ export class SpMenu extends React.Component<{
|
|||
title?: string
|
||||
style?: CSSProperties
|
||||
items?: string[]
|
||||
disabled?: boolean[]
|
||||
disabled?: boolean
|
||||
disabled_items?: boolean[]
|
||||
label_item?: string
|
||||
onChange?: any
|
||||
selected_index?: number
|
||||
|
|
@ -238,6 +241,7 @@ export class SpMenu extends React.Component<{
|
|||
title={this.props.title}
|
||||
size={this.props.size || 'm'}
|
||||
style={this.props.style}
|
||||
disabled={this.props.disabled ? 'disabled' : undefined}
|
||||
// style={{ width: '199px', marginRight: '5px' }}
|
||||
>
|
||||
<sp-menu id={this.props.id} slot="options">
|
||||
|
|
@ -263,7 +267,7 @@ export class SpMenu extends React.Component<{
|
|||
: undefined
|
||||
}
|
||||
disabled={
|
||||
this.props.disabled?.[index]
|
||||
this.props.disabled_items?.[index]
|
||||
? 'disabled'
|
||||
: undefined
|
||||
}
|
||||
|
|
@ -492,8 +496,7 @@ export const ScriptInstallComponent = observer(
|
|||
Automatic1111 webui
|
||||
</sp-label>
|
||||
<button
|
||||
className="btnSquare refreshButton"
|
||||
id="btnResetSettings"
|
||||
className="btnSquare refreshButton btnResetSettings"
|
||||
title="Refresh the ADetailer Extension"
|
||||
onClick={onRefreshHandler}
|
||||
></button>
|
||||
|
|
@ -501,3 +504,193 @@ export const ScriptInstallComponent = observer(
|
|||
)
|
||||
}
|
||||
)
|
||||
|
||||
@observer
|
||||
export class SearchableMenu extends React.Component<{
|
||||
allItems: string[]
|
||||
placeholder: string
|
||||
onChange?: any
|
||||
selected_item?: string
|
||||
onSelectItemFailure?: any
|
||||
// default_value?: string
|
||||
// searchQuery: string
|
||||
}> {
|
||||
state = {
|
||||
selectedItem: this.props.allItems ? this.props.allItems[0] : undefined,
|
||||
searchItems: this.props.allItems,
|
||||
// searchQuery: this.props.searchQuery,
|
||||
searchQuery: '',
|
||||
openMenu: false,
|
||||
}
|
||||
selectItem(selected_item: string) {
|
||||
let final_value = this.props.allItems.includes(selected_item)
|
||||
? selected_item
|
||||
: this.props.onSelectItemFailure && this.props.onSelectItemFailure()
|
||||
|
||||
this.setState({ searchQuery: final_value })
|
||||
}
|
||||
componentDidMount(): void {
|
||||
if (this.props.selected_item) {
|
||||
// console.log('selected_item has changed:', this.props.selected_item)
|
||||
this.selectItem(this.props.selected_item)
|
||||
}
|
||||
}
|
||||
componentDidUpdate(prevProps: any, prevState: { searchQuery: string }) {
|
||||
if (prevState.searchQuery !== this.state.searchQuery) {
|
||||
this.searchItem(this.state.searchQuery)
|
||||
}
|
||||
if (prevProps.selected_item !== this.props.selected_item) {
|
||||
console.log('selected_item has changed:', this.props.selected_item)
|
||||
|
||||
if (this.props.selected_item !== undefined) {
|
||||
this.selectItem(this.props.selected_item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// searchItem = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
searchItem = (searchQuery: string) => {
|
||||
console.log('onInput')
|
||||
|
||||
// const filter = event.currentTarget.value.toUpperCase()
|
||||
const filter = searchQuery.toUpperCase()
|
||||
|
||||
const searchItems = this.props.allItems.filter((item) =>
|
||||
item.toUpperCase().includes(filter)
|
||||
)
|
||||
this.setState({ searchItems: searchItems })
|
||||
|
||||
console.log(
|
||||
'this.props.searchItems.length: ',
|
||||
this.state.searchItems.length
|
||||
)
|
||||
|
||||
this.setState({
|
||||
openMenu: this.state.searchItems.length > 0 ? true : false,
|
||||
})
|
||||
|
||||
console.log('this.state.openMenu: ', this.state.openMenu)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
zIndex: 1000,
|
||||
// position: 'absolute',
|
||||
}}
|
||||
>
|
||||
<div style={{ position: 'relative', flex: 1, width: '100%' }}>
|
||||
<SpTextfield
|
||||
type="text"
|
||||
title={this.state.searchQuery}
|
||||
style={{ width: '100%' }}
|
||||
value={this.state.searchQuery}
|
||||
placeholder={this.props.placeholder}
|
||||
onInput={(evt: any) => {
|
||||
this.setState({ searchQuery: evt.target.value })
|
||||
// this.searchItem(evt.taret)
|
||||
console.log('onInput:', evt.target.value)
|
||||
|
||||
console.log(
|
||||
'this.state.searchQuery: ',
|
||||
this.state.searchQuery
|
||||
)
|
||||
}}
|
||||
onChange={(evt: any) => {
|
||||
this.setState({ searchQuery: evt.target.value })
|
||||
console.log('onChange:', evt.target.value)
|
||||
|
||||
console.log(
|
||||
'this.state.searchQuery: ',
|
||||
this.state.searchQuery
|
||||
)
|
||||
}}
|
||||
onFocus={(evt: any) => {
|
||||
console.log('onFocus:', evt.target.value)
|
||||
if (evt.target.value === '') {
|
||||
this.setState({
|
||||
searchItems: this.props.allItems,
|
||||
})
|
||||
}
|
||||
this.setState({ openMenu: true })
|
||||
console.log(
|
||||
'this.state.searchQuery: ',
|
||||
this.state.searchQuery
|
||||
)
|
||||
}}
|
||||
onBlur={(evt: any) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
console.log('onBlur:', evt.target.value)
|
||||
|
||||
const state_values: Record<string, any> = {}
|
||||
if (
|
||||
!this.props.allItems.includes(
|
||||
this.state.searchQuery
|
||||
)
|
||||
) {
|
||||
state_values.searchQuery = ''
|
||||
|
||||
if (this.props.onSelectItemFailure) {
|
||||
state_values.searchQuery =
|
||||
this.props.onSelectItemFailure()
|
||||
}
|
||||
}
|
||||
state_values.openMenu = false
|
||||
this.setState(state_values)
|
||||
|
||||
console.log(
|
||||
'this.state.searchQuery: ',
|
||||
this.state.searchQuery
|
||||
)
|
||||
},
|
||||
|
||||
200
|
||||
)
|
||||
}}
|
||||
></SpTextfield>
|
||||
|
||||
<ul
|
||||
id="myMenu"
|
||||
style={{
|
||||
// position: 'absolute',
|
||||
width: '100%',
|
||||
display: this.state.openMenu ? void 0 : 'none',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
{this.state.searchItems.map((item: string, index) => (
|
||||
<li
|
||||
key={index}
|
||||
title={item}
|
||||
onClick={() => {
|
||||
console.log('onClick:')
|
||||
|
||||
this.setState({
|
||||
searchQuery: item,
|
||||
openMenu: false,
|
||||
})
|
||||
console.log(
|
||||
'this.state.searchQuery: ',
|
||||
this.state.searchQuery
|
||||
)
|
||||
console.log('item: ', item)
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(item)
|
||||
}
|
||||
}}
|
||||
style={{ zIndex: 1000 }}
|
||||
>
|
||||
<a href="#" style={{ fontSize: '12px' }}>
|
||||
{item}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component, ErrorInfo, ReactNode } from 'react'
|
||||
import { refreshUI } from '../sd_tab/util'
|
||||
|
||||
interface Props {
|
||||
children: ReactNode
|
||||
|
|
@ -6,14 +7,21 @@ interface Props {
|
|||
|
||||
interface State {
|
||||
hasError: boolean
|
||||
key: number
|
||||
}
|
||||
interface State {
|
||||
hasError: boolean
|
||||
key: number
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends Component<Props, State> {
|
||||
public state: State = {
|
||||
hasError: false,
|
||||
key: 0,
|
||||
}
|
||||
|
||||
public static getDerivedStateFromError(_: Error): State {
|
||||
public static getDerivedStateFromError(_: Error): Partial<State> {
|
||||
// When an error occurs, we update state so the next render will show the fallback UI.
|
||||
return { hasError: true }
|
||||
}
|
||||
|
||||
|
|
@ -21,11 +29,25 @@ export class ErrorBoundary extends Component<Props, State> {
|
|||
console.error('Uncaught error:', error, errorInfo)
|
||||
}
|
||||
|
||||
handleRefresh = () => {
|
||||
this.setState((prevState) => ({
|
||||
hasError: false, // reset the error state
|
||||
key: prevState.key + 1, // increment key to remount children
|
||||
}))
|
||||
// await refreshUI()
|
||||
}
|
||||
|
||||
public render() {
|
||||
if (this.state.hasError) {
|
||||
return <h1>Sorry.. there was an error</h1>
|
||||
return (
|
||||
<div>
|
||||
<h1>Sorry.. there was an error</h1>
|
||||
<button onClick={this.handleRefresh}>Refresh</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return this.props.children
|
||||
// The key prop causes a remount of children when it changes
|
||||
return <div key={this.state.key}>{this.props.children}</div>
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ export class Grid extends React.Component<{
|
|||
event
|
||||
)
|
||||
}
|
||||
this.props?.callback(index, event) //todo: is this a typo why do we call callback twice?
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { storage } from 'uxp'
|
|||
|
||||
declare let g_sd_url: string
|
||||
export async function requestGet(url: string) {
|
||||
let json = null
|
||||
let data = null
|
||||
|
||||
const full_url = url
|
||||
try {
|
||||
|
|
@ -11,14 +11,31 @@ export async function requestGet(url: string) {
|
|||
return null
|
||||
}
|
||||
|
||||
json = await request.json()
|
||||
const contentType = request.headers.get('content-type')
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
data = await request.json()
|
||||
} else if (
|
||||
contentType &&
|
||||
contentType.includes('application/octet-stream')
|
||||
) {
|
||||
data = await request.arrayBuffer()
|
||||
} else if (
|
||||
contentType &&
|
||||
(contentType.includes('image/jpeg') ||
|
||||
contentType.includes('image/png'))
|
||||
) {
|
||||
data = await request.arrayBuffer()
|
||||
} else {
|
||||
data = await request.text()
|
||||
}
|
||||
|
||||
// console.log('json: ', json)
|
||||
// console.log('data: ', data)
|
||||
} catch (e) {
|
||||
console.warn(`issues requesting from ${full_url}`, e)
|
||||
}
|
||||
return json
|
||||
return data
|
||||
}
|
||||
|
||||
export async function requestPost(url: string, payload: any) {
|
||||
let json = null
|
||||
|
||||
|
|
|
|||
|
|
@ -49,3 +49,21 @@ export function autoResize(textarea: any, text_content: string, delay = 300) {
|
|||
export async function urlToCanvas(url: string, image_name = 'image.png') {
|
||||
await io.IO.urlToLayer(url, image_name)
|
||||
}
|
||||
|
||||
export const copyJson = (originalObject: any) =>
|
||||
JSON.parse(JSON.stringify(originalObject))
|
||||
|
||||
export function base64ToBase64Url(base64_image: string) {
|
||||
return 'data:image/png;base64,' + base64_image
|
||||
}
|
||||
export function base64UrlToBase64(base64_url: string) {
|
||||
const base64_image = base64_url.replace('data:image/png;base64,', '')
|
||||
return base64_image
|
||||
}
|
||||
|
||||
export function newOutputImageName(format = 'png') {
|
||||
const random_id = Math.floor(Math.random() * 100000000000 + 1) // Date.now() doesn't have enough resolution to avoid duplicate
|
||||
const image_name = `output- ${Date.now()}-${random_id}.${format}`
|
||||
console.log('generated image name:', image_name)
|
||||
return image_name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,10 @@ export async function requestGetModels() {
|
|||
let json = []
|
||||
const full_url = `${g_sd_url}/sdapi/v1/sd-models`
|
||||
try {
|
||||
let request = await fetch(full_url)
|
||||
json = await request.json()
|
||||
let res = await fetch(full_url)
|
||||
if (res.status == 200) {
|
||||
json = await res.json()
|
||||
}
|
||||
console.log('models json:')
|
||||
console.dir(json)
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -136,3 +136,9 @@ export const resetViewer = () => {
|
|||
init_store.data.images = []
|
||||
init_store.data.thumbnails = []
|
||||
}
|
||||
|
||||
export default {
|
||||
store,
|
||||
init_store,
|
||||
mask_store,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -890,10 +890,17 @@ async function createThumbnail(base64Image, width = 100) {
|
|||
return thumbnail
|
||||
}
|
||||
|
||||
async function getImageFromCanvas() {
|
||||
const width = html_manip.getWidth()
|
||||
const height = html_manip.getHeight()
|
||||
async function getImageFromCanvas(scale_to_sliders = true) {
|
||||
let width
|
||||
let height
|
||||
const selectionInfo = await psapi.getSelectionInfoExe()
|
||||
if (scale_to_sliders) {
|
||||
width = html_manip.getWidth()
|
||||
height = html_manip.getHeight()
|
||||
} else {
|
||||
width = selectionInfo.width
|
||||
height = selectionInfo.height
|
||||
}
|
||||
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
||||
width,
|
||||
height,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"new_version": "v1.3.3",
|
||||
"new_version": "v1.4.0",
|
||||
"update_message": "Your version is outdated.Please visit our Github page and download the one click installer / .ccx file.\nRun the .ccx file and it will automatically update the current version of your plug in. No data will be lost."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ async function getSettings(session_data) {
|
|||
|
||||
try {
|
||||
const extension_type = settings_tab_ts.store.data.extension_type // get the extension type
|
||||
payload['selection_info'] = session_data.selectionInfo
|
||||
payload['selection_info'] = session_data?.selectionInfo
|
||||
const numberOfBatchSize = parseInt(sd_tab_store.data.batch_size)
|
||||
|
||||
const prompt = multiPrompts.getPrompt().positive
|
||||
|
|
@ -195,11 +195,14 @@ async function getSettings(session_data) {
|
|||
|
||||
function calculateSeed(init_seed, batch_index, batch_size) {
|
||||
if (init_seed === -1) return -1
|
||||
const seed = init_seed + batch_index * batch_size
|
||||
// const seed = init_seed + batch_index * batch_size
|
||||
const seed = init_seed + BigInt(batch_index) * BigInt(batch_size)
|
||||
return seed
|
||||
}
|
||||
|
||||
const init_seed = parseInt(sd_tab_store.data.seed)
|
||||
// const init_seed = parseInt(sd_tab_store.data.seed)
|
||||
const init_seed = BigInt(sd_tab_store.data.seed)
|
||||
|
||||
const seed = calculateSeed(
|
||||
init_seed,
|
||||
g_current_batch_index,
|
||||
|
|
@ -247,7 +250,8 @@ async function getSettings(session_data) {
|
|||
|
||||
const sampler_name = sd_tab_store.data.sampler_name
|
||||
|
||||
const mode = sd_tab_store.data.rb_mode
|
||||
const mode = session_data?.rb_mode || sd_tab_store.data.rb_mode // Use the 'rb_mode' from the session, if not available, fallback to the 'rb_mode' from the interface.
|
||||
|
||||
const b_restore_faces = sd_tab_store.data.restore_faces
|
||||
|
||||
let denoising_strength = h_denoising_strength
|
||||
|
|
@ -412,6 +416,8 @@ async function getSettings(session_data) {
|
|||
payload['original_negative_prompt'] = negative_prompt
|
||||
}
|
||||
|
||||
payload['clip_skip'] =
|
||||
settings_tab_ts.store.data.CLIP_stop_at_last_layers
|
||||
payload = {
|
||||
...payload,
|
||||
// prompt: prompt,
|
||||
|
|
@ -424,8 +430,8 @@ async function getSettings(session_data) {
|
|||
denoising_strength: denoising_strength,
|
||||
batch_size: numberOfBatchSize,
|
||||
cfg_scale: cfg_scale,
|
||||
seed: seed,
|
||||
// mask_blur: mask_blur, // don't use auto1111 blur, instead use Auto-Photoshop-SD blur
|
||||
seed: seed.toString(),
|
||||
mask_blur: 4, //mask_blur, // don't use auto1111 blur, instead use Auto-Photoshop-SD blur
|
||||
use_sharp_mask: use_sharp_mask,
|
||||
use_prompt_shortcut: bUsePromptShortcut,
|
||||
prompt_shortcut_ui_dict: prompt_shortcut_ui_dict,
|
||||
|
|
|
|||
Loading…
Reference in New Issue