Compare commits
46
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5ecf56f8e | ||
|
|
74f940e818 | ||
|
|
71cfb9ebac | ||
|
|
b04a36be37 | ||
|
|
e1d49c5262 | ||
|
|
6cd613811b | ||
|
|
e560eb8b60 | ||
|
|
e12793e937 | ||
|
|
c8c662901b | ||
|
|
39ce23f42d | ||
|
|
9c92a1a9aa | ||
|
|
8ffc07b7b1 | ||
|
|
0065327726 | ||
|
|
1a0353675d | ||
|
|
6fa20d51dc | ||
|
|
79e7c39298 | ||
|
|
03faf20251 | ||
|
|
8708386609 | ||
|
|
d4205e66fa | ||
|
|
d6fd71f36f | ||
|
|
7ef361dfc3 | ||
|
|
c82e32652e | ||
|
|
02f58cde8d | ||
|
|
8e8d64199a | ||
|
|
0ce9e05a42 | ||
|
|
6e86fc9fd0 | ||
|
|
ebf19c1145 | ||
|
|
a2d084a07c | ||
|
|
42b7902922 | ||
|
|
08e27c3252 | ||
|
|
ea2426fa61 | ||
|
|
d26d89377b | ||
|
|
03738668c0 | ||
|
|
19fc3e8279 | ||
|
|
e16b9dc819 | ||
|
|
77cf346d93 | ||
|
|
75b90a5e40 | ||
|
|
6d1c01c955 | ||
|
|
dec7584903 | ||
|
|
ae32b8a53f | ||
|
|
cae09e1651 | ||
|
|
a213d3a21c | ||
|
|
25eb1e3d90 | ||
|
|
34d5a31ea2 | ||
|
|
3582befdcd | ||
|
|
b0765a6788 |
@@ -2,7 +2,7 @@
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
labels: bug-report
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
@@ -6,6 +6,7 @@ __pycache__
|
||||
/model.ckpt
|
||||
/models/*.ckpt
|
||||
/GFPGANv1.3.pth
|
||||
/gfpgan/weights/*.pth
|
||||
/ui-config.json
|
||||
/outputs
|
||||
/config.json
|
||||
|
||||
@@ -51,7 +51,10 @@ A browser interface based on Gradio library for Stable Diffusion.
|
||||
## Installation and Running
|
||||
Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs.
|
||||
|
||||
Alternatively, use [Google Colab](https://colab.research.google.com/drive/1Iy-xW9t1-OQWhb0hNxueGij8phCyluOh).
|
||||
Alternatively, use Google Colab:
|
||||
|
||||
- [Colab, maintained by Akaibu](https://colab.research.google.com/drive/1kw3egmSn-KgWsikYvOMjJkVDsPLjEMzl)
|
||||
- [Colab, original by me, outdated](https://colab.research.google.com/drive/1Iy-xW9t1-OQWhb0hNxueGij8phCyluOh).
|
||||
|
||||
### Automatic Installation on Windows
|
||||
1. Install [Python 3.10.6](https://www.python.org/downloads/windows/), checking "Add Python to PATH"
|
||||
|
||||
@@ -18,9 +18,9 @@ function dimensionChange(e,dimname){
|
||||
return;
|
||||
}
|
||||
|
||||
var img2imgMode = gradioApp().querySelector("input[name=radio-img2img_mode]:checked")
|
||||
var img2imgMode = gradioApp().querySelector('#mode_img2img.tabs > div > button.rounded-t-lg.border-gray-200')
|
||||
if(img2imgMode){
|
||||
img2imgMode=img2imgMode.value
|
||||
img2imgMode=img2imgMode.innerText
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
@@ -30,12 +30,10 @@ function dimensionChange(e,dimname){
|
||||
|
||||
var targetElement = null;
|
||||
|
||||
if(img2imgMode=='Redraw whole image' && redrawImage){
|
||||
if(img2imgMode=='img2img' && redrawImage){
|
||||
targetElement = redrawImage;
|
||||
}else if(img2imgMode=='Inpaint a part of image' && inpaintImage){
|
||||
}else if(img2imgMode=='Inpaint' && inpaintImage){
|
||||
targetElement = inpaintImage;
|
||||
}else if(img2imgMode=='SD upscale' && redrawImage){
|
||||
targetElement = redrawImage;
|
||||
}
|
||||
|
||||
if(targetElement){
|
||||
@@ -119,6 +117,3 @@ onUiUpdate(function(){
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -13,6 +13,8 @@ titles = {
|
||||
"Seed": "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result",
|
||||
"\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time",
|
||||
"\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed",
|
||||
"\u{1f3a8}": "Add a random artist to the prompt.",
|
||||
"\u2199\ufe0f": "Read generation parameters from prompt into user interface.",
|
||||
|
||||
"Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt",
|
||||
"SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back",
|
||||
@@ -48,8 +50,6 @@ titles = {
|
||||
"Tiling": "Produce an image that can be tiled.",
|
||||
"Tile overlap": "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.",
|
||||
|
||||
"Roll": "Add a random artist to the prompt.",
|
||||
|
||||
"Variation seed": "Seed of a different picture to be mixed into the generation.",
|
||||
"Variation strength": "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).",
|
||||
"Resize seed from height": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution",
|
||||
@@ -59,6 +59,7 @@ titles = {
|
||||
|
||||
"Images filename pattern": "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_spaces], [width], [height], [sampler], [seed], [model_hash], [prompt_words], [date]; leave empty for default.",
|
||||
"Directory name pattern": "Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg], [prompt], [prompt_spaces], [width], [height], [sampler], [seed], [model_hash], [prompt_words], [date]; leave empty for default.",
|
||||
"Max prompt words": "Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle",
|
||||
|
||||
"Loopback": "Process an image, use it as an input, repeat.",
|
||||
"Loops": "How many times to repeat processing an image and using it as input for the next iteration",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668
|
||||
* @see https://github.com/gradio-app/gradio/issues/1721
|
||||
*/
|
||||
window.addEventListener( 'resize', () => imageMaskResize());
|
||||
function imageMaskResize() {
|
||||
const canvases = gradioApp().querySelectorAll('#img2maskimg .touch-none canvas');
|
||||
if ( ! canvases.length ) {
|
||||
canvases_fixed = false;
|
||||
window.removeEventListener( 'resize', imageMaskResize );
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = canvases[0].closest('.touch-none');
|
||||
const previewImage = wrapper.previousElementSibling;
|
||||
|
||||
if ( ! previewImage.complete ) {
|
||||
previewImage.addEventListener( 'load', () => imageMaskResize());
|
||||
return;
|
||||
}
|
||||
|
||||
const w = previewImage.width;
|
||||
const h = previewImage.height;
|
||||
const nw = previewImage.naturalWidth;
|
||||
const nh = previewImage.naturalHeight;
|
||||
const portrait = nh > nw;
|
||||
const factor = portrait;
|
||||
|
||||
const wW = Math.min(w, portrait ? h/nh*nw : w/nw*nw);
|
||||
const wH = Math.min(h, portrait ? h/nh*nh : w/nw*nh);
|
||||
|
||||
wrapper.style.width = `${wW}px`;
|
||||
wrapper.style.height = `${wH}px`;
|
||||
wrapper.style.left = `${(w-wW)/2}px`;
|
||||
wrapper.style.top = `${(h-wH)/2}px`;
|
||||
|
||||
canvases.forEach( c => {
|
||||
c.style.width = c.style.height = '';
|
||||
c.style.maxWidth = '100%';
|
||||
c.style.maxHeight = '100%';
|
||||
c.style.objectFit = 'contain';
|
||||
});
|
||||
}
|
||||
|
||||
onUiUpdate(() => imageMaskResize());
|
||||
@@ -22,10 +22,22 @@ function negmod(n, m) {
|
||||
}
|
||||
|
||||
function modalImageSwitch(offset){
|
||||
var galleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all")
|
||||
var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all")
|
||||
var galleryButtons = []
|
||||
allgalleryButtons.forEach(function(elem){
|
||||
if(elem.parentElement.offsetParent){
|
||||
galleryButtons.push(elem);
|
||||
}
|
||||
})
|
||||
|
||||
if(galleryButtons.length>1){
|
||||
var currentButton = gradioApp().querySelector(".gallery-item.transition-all.\\!ring-2")
|
||||
var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
|
||||
var currentButton = null
|
||||
allcurrentButtons.forEach(function(elem){
|
||||
if(elem.parentElement.offsetParent){
|
||||
currentButton = elem;
|
||||
}
|
||||
})
|
||||
|
||||
var result = -1
|
||||
galleryButtons.forEach(function(v, i){ if(v==currentButton) { result = i } })
|
||||
|
||||
@@ -2,7 +2,19 @@
|
||||
|
||||
let lastHeadImg = null;
|
||||
|
||||
notificationButton = null
|
||||
|
||||
onUiUpdate(function(){
|
||||
if(notificationButton == null){
|
||||
notificationButton = gradioApp().getElementById('request_notifications')
|
||||
|
||||
if(notificationButton != null){
|
||||
notificationButton.addEventListener('click', function (evt) {
|
||||
Notification.requestPermission();
|
||||
},true);
|
||||
}
|
||||
}
|
||||
|
||||
const galleryPreviews = gradioApp().querySelectorAll('img.h-full.w-full.overflow-hidden');
|
||||
|
||||
if (galleryPreviews == null) return;
|
||||
|
||||
+27
-29
@@ -1,53 +1,51 @@
|
||||
// code related to showing and updating progressbar shown as the image is being made
|
||||
global_progressbar = null
|
||||
global_progressbars = {}
|
||||
|
||||
onUiUpdate(function(){
|
||||
progressbar = gradioApp().getElementById('progressbar')
|
||||
progressDiv = gradioApp().querySelectorAll('.progressDiv').length > 0;
|
||||
interrupt = gradioApp().getElementById('interrupt')
|
||||
if(progressbar!= null && progressbar != global_progressbar){
|
||||
global_progressbar = progressbar
|
||||
function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_interrupt, id_preview, id_gallery){
|
||||
var progressbar = gradioApp().getElementById(id_progressbar)
|
||||
var interrupt = gradioApp().getElementById(id_interrupt)
|
||||
if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){
|
||||
global_progressbars[id_progressbar] = progressbar
|
||||
|
||||
var mutationObserver = new MutationObserver(function(m){
|
||||
txt2img_preview = gradioApp().getElementById('txt2img_preview')
|
||||
txt2img_gallery = gradioApp().getElementById('txt2img_gallery')
|
||||
img2img_preview = gradioApp().getElementById('img2img_preview')
|
||||
img2img_gallery = gradioApp().getElementById('img2img_gallery')
|
||||
preview = gradioApp().getElementById(id_preview)
|
||||
gallery = gradioApp().getElementById(id_gallery)
|
||||
|
||||
if(txt2img_preview != null && txt2img_gallery != null){
|
||||
txt2img_preview.style.width = txt2img_gallery.clientWidth + "px"
|
||||
txt2img_preview.style.height = txt2img_gallery.clientHeight + "px"
|
||||
if(preview != null && gallery != null){
|
||||
preview.style.width = gallery.clientWidth + "px"
|
||||
preview.style.height = gallery.clientHeight + "px"
|
||||
|
||||
var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0;
|
||||
if(!progressDiv){
|
||||
interrupt.style.display = "none"
|
||||
}
|
||||
}
|
||||
|
||||
if(img2img_preview != null && img2img_gallery != null){
|
||||
img2img_preview.style.width = img2img_gallery.clientWidth + "px"
|
||||
img2img_preview.style.height = img2img_gallery.clientHeight + "px"
|
||||
if(!progressDiv){
|
||||
interrupt.style.display = "none"
|
||||
}
|
||||
}
|
||||
|
||||
window.setTimeout(requestMoreProgress, 500)
|
||||
window.setTimeout(function(){ requestMoreProgress(id_part, id_progressbar_span, id_interrupt) }, 500)
|
||||
});
|
||||
mutationObserver.observe( progressbar, { childList:true, subtree:true })
|
||||
}
|
||||
}
|
||||
|
||||
onUiUpdate(function(){
|
||||
check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery')
|
||||
check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery')
|
||||
})
|
||||
function requestMoreProgress(){
|
||||
btn = gradioApp().getElementById("check_progress");
|
||||
|
||||
function requestMoreProgress(id_part, id_progressbar_span, id_interrupt){
|
||||
btn = gradioApp().getElementById(id_part+"_check_progress");
|
||||
if(btn==null) return;
|
||||
|
||||
btn.click();
|
||||
progressDiv = gradioApp().querySelectorAll('.progressDiv').length > 0;
|
||||
if(progressDiv){
|
||||
var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0;
|
||||
var interrupt = gradioApp().getElementById(id_interrupt)
|
||||
if(progressDiv && interrupt){
|
||||
interrupt.style.display = "block"
|
||||
}
|
||||
}
|
||||
|
||||
function requestProgress(){
|
||||
btn = gradioApp().getElementById("check_progress_initial");
|
||||
function requestProgress(id_part){
|
||||
btn = gradioApp().getElementById(id_part+"_check_progress_initial");
|
||||
if(btn==null) return;
|
||||
|
||||
btn.click();
|
||||
|
||||
+48
-4
@@ -25,13 +25,57 @@ function extract_image_from_gallery(gallery){
|
||||
return gallery[index];
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_img2img(gallery){
|
||||
function args_to_array(args){
|
||||
res = []
|
||||
for(var i=0;i<args.length;i++){
|
||||
res.push(args[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function switch_to_txt2img(){
|
||||
gradioApp().querySelectorAll('button')[0].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_img2img_img2img(){
|
||||
gradioApp().querySelectorAll('button')[1].click();
|
||||
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[0].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_img2img_inpaint(){
|
||||
gradioApp().querySelectorAll('button')[1].click();
|
||||
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[1].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_extras(){
|
||||
gradioApp().querySelectorAll('button')[2].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_txt2img(gallery){
|
||||
switch_to_txt2img()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_img2img(gallery){
|
||||
switch_to_img2img_img2img()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_inpaint(gallery){
|
||||
switch_to_img2img_inpaint()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_extras(gallery){
|
||||
gradioApp().querySelectorAll('button')[2].click();
|
||||
switch_to_extras()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
@@ -79,13 +123,13 @@ function create_submit_args(args){
|
||||
}
|
||||
|
||||
function submit(){
|
||||
requestProgress()
|
||||
requestProgress('txt2img')
|
||||
|
||||
return create_submit_args(arguments)
|
||||
}
|
||||
|
||||
function submit_img2img(){
|
||||
requestProgress()
|
||||
requestProgress('img2img')
|
||||
|
||||
res = create_submit_args(arguments)
|
||||
|
||||
|
||||
+4
-2
@@ -102,6 +102,7 @@ def run_pnginfo(image):
|
||||
return '', '', ''
|
||||
|
||||
items = image.info
|
||||
geninfo = ''
|
||||
|
||||
if "exif" in image.info:
|
||||
exif = piexif.load(image.info["exif"])
|
||||
@@ -111,13 +112,14 @@ def run_pnginfo(image):
|
||||
except ValueError:
|
||||
exif_comment = exif_comment.decode('utf8', errors="ignore")
|
||||
|
||||
|
||||
items['exif comment'] = exif_comment
|
||||
geninfo = exif_comment
|
||||
|
||||
for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
|
||||
'loop', 'background', 'timestamp', 'duration']:
|
||||
items.pop(field, None)
|
||||
|
||||
geninfo = items.get('parameters', geninfo)
|
||||
|
||||
info = ''
|
||||
for key, text in items.items():
|
||||
@@ -132,4 +134,4 @@ def run_pnginfo(image):
|
||||
message = "Nothing found in the image."
|
||||
info = f"<div><p>{message}<p></div>"
|
||||
|
||||
return '', '', info
|
||||
return '', geninfo, info
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
from collections import namedtuple
|
||||
import re
|
||||
import gradio as gr
|
||||
|
||||
re_param = re.compile(r"\s*([\w ]+):\s*([^,]+)(?:,|$)")
|
||||
re_imagesize = re.compile(r"^(\d+)x(\d+)$")
|
||||
|
||||
|
||||
def parse_generation_parameters(x: str):
|
||||
"""parses generation parameters string, the one you see in text field under the picture in UI:
|
||||
```
|
||||
girl with an artist's beret, determined, blue eyes, desert scene, computer monitors, heavy makeup, by Alphonse Mucha and Charlie Bowater, ((eyeshadow)), (coquettish), detailed, intricate
|
||||
Negative prompt: ugly, fat, obese, chubby, (((deformed))), [blurry], bad anatomy, disfigured, poorly drawn face, mutation, mutated, (extra_limb), (ugly), (poorly drawn hands), messy drawing
|
||||
Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model hash: 45dee52b
|
||||
```
|
||||
|
||||
returns a dict with field values
|
||||
"""
|
||||
|
||||
res = {}
|
||||
|
||||
prompt = ""
|
||||
negative_prompt = ""
|
||||
|
||||
done_with_prompt = False
|
||||
|
||||
*lines, lastline = x.strip().split("\n")
|
||||
for i, line in enumerate(lines):
|
||||
line = line.strip()
|
||||
if line.startswith("Negative prompt:"):
|
||||
done_with_prompt = True
|
||||
line = line[16:].strip()
|
||||
|
||||
if done_with_prompt:
|
||||
negative_prompt += line
|
||||
else:
|
||||
prompt += line
|
||||
|
||||
if len(prompt) > 0:
|
||||
res["Prompt"] = prompt
|
||||
|
||||
if len(negative_prompt) > 0:
|
||||
res["Negative prompt"] = negative_prompt
|
||||
|
||||
for k, v in re_param.findall(lastline):
|
||||
m = re_imagesize.match(v)
|
||||
if m is not None:
|
||||
res[k+"-1"] = m.group(1)
|
||||
res[k+"-2"] = m.group(2)
|
||||
else:
|
||||
res[k] = v
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def connect_paste(button, d, input_comp, js=None):
|
||||
items = []
|
||||
outputs = []
|
||||
|
||||
def paste_func(prompt):
|
||||
params = parse_generation_parameters(prompt)
|
||||
res = []
|
||||
|
||||
for key, output in zip(items, outputs):
|
||||
v = params.get(key, None)
|
||||
|
||||
if v is None:
|
||||
res.append(gr.update())
|
||||
else:
|
||||
try:
|
||||
valtype = type(output.value)
|
||||
val = valtype(v)
|
||||
res.append(gr.update(value=val))
|
||||
except Exception:
|
||||
res.append(gr.update())
|
||||
|
||||
return res
|
||||
|
||||
for k, v in d.items():
|
||||
items.append(k)
|
||||
outputs.append(v)
|
||||
|
||||
button.click(
|
||||
fn=paste_func,
|
||||
_js=js,
|
||||
inputs=[input_comp],
|
||||
outputs=outputs,
|
||||
)
|
||||
+13
-6
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from glob import glob
|
||||
|
||||
from modules import shared, devices
|
||||
from modules.shared import cmd_opts
|
||||
@@ -11,14 +12,20 @@ import modules.face_restoration
|
||||
def gfpgan_model_path():
|
||||
from modules.shared import cmd_opts
|
||||
|
||||
filemask = 'GFPGAN*.pth'
|
||||
|
||||
if cmd_opts.gfpgan_model is not None:
|
||||
return cmd_opts.gfpgan_model
|
||||
|
||||
places = [script_path, '.', os.path.join(cmd_opts.gfpgan_dir, 'experiments/pretrained_models')]
|
||||
files = [cmd_opts.gfpgan_model] + [os.path.join(dirname, cmd_opts.gfpgan_model) for dirname in places]
|
||||
found = [x for x in files if os.path.exists(x)]
|
||||
|
||||
if len(found) == 0:
|
||||
raise Exception("GFPGAN model not found in paths: " + ", ".join(files))
|
||||
filename = None
|
||||
for place in places:
|
||||
filename = next(iter(glob(os.path.join(place, filemask))), None)
|
||||
if filename is not None:
|
||||
break
|
||||
|
||||
return found[0]
|
||||
return filename
|
||||
|
||||
|
||||
loaded_gfpgan_model = None
|
||||
@@ -34,7 +41,7 @@ def gfpgan():
|
||||
if gfpgan_constructor is None:
|
||||
return None
|
||||
|
||||
model = gfpgan_constructor(model_path=gfpgan_model_path(), upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None)
|
||||
model = gfpgan_constructor(model_path=gfpgan_model_path() or 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth', upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None)
|
||||
model.gfpgan.to(shared.device)
|
||||
loaded_gfpgan_model = model
|
||||
|
||||
|
||||
+16
-6
@@ -209,8 +209,16 @@ def draw_prompt_matrix(im, width, height, all_prompts):
|
||||
|
||||
|
||||
def resize_image(resize_mode, im, width, height):
|
||||
def resize(im, w, h):
|
||||
if opts.upscaler_for_img2img is None or opts.upscaler_for_img2img == "None" or im.mode == 'L':
|
||||
return im.resize((w, h), resample=LANCZOS)
|
||||
|
||||
upscaler = [x for x in shared.sd_upscalers if x.name == opts.upscaler_for_img2img][0]
|
||||
return upscaler.upscale(im, w, h)
|
||||
|
||||
if resize_mode == 0:
|
||||
res = im.resize((width, height), resample=LANCZOS)
|
||||
res = resize(im, width, height)
|
||||
|
||||
elif resize_mode == 1:
|
||||
ratio = width / height
|
||||
src_ratio = im.width / im.height
|
||||
@@ -218,9 +226,10 @@ def resize_image(resize_mode, im, width, height):
|
||||
src_w = width if ratio > src_ratio else im.width * height // im.height
|
||||
src_h = height if ratio <= src_ratio else im.height * width // im.width
|
||||
|
||||
resized = im.resize((src_w, src_h), resample=LANCZOS)
|
||||
resized = resize(im, src_w, src_h)
|
||||
res = Image.new("RGB", (width, height))
|
||||
res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2))
|
||||
|
||||
else:
|
||||
ratio = width / height
|
||||
src_ratio = im.width / im.height
|
||||
@@ -228,7 +237,7 @@ def resize_image(resize_mode, im, width, height):
|
||||
src_w = width if ratio < src_ratio else im.width * height // im.height
|
||||
src_h = height if ratio >= src_ratio else im.height * width // im.width
|
||||
|
||||
resized = im.resize((src_w, src_h), resample=LANCZOS)
|
||||
resized = resize(im, src_w, src_h)
|
||||
res = Image.new("RGB", (width, height))
|
||||
res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2))
|
||||
|
||||
@@ -249,7 +258,6 @@ invalid_filename_prefix = ' '
|
||||
invalid_filename_postfix = ' .'
|
||||
re_nonletters = re.compile(r'[\s'+string.punctuation+']+')
|
||||
max_filename_part_length = 128
|
||||
max_prompt_words = 8
|
||||
|
||||
|
||||
def sanitize_filename_part(text, replace_spaces=True):
|
||||
@@ -263,6 +271,8 @@ def sanitize_filename_part(text, replace_spaces=True):
|
||||
|
||||
|
||||
def apply_filename_pattern(x, p, seed, prompt):
|
||||
max_prompt_words = opts.directories_max_prompt_words
|
||||
|
||||
if seed is not None:
|
||||
x = x.replace("[seed]", str(seed))
|
||||
|
||||
@@ -311,7 +321,7 @@ def get_next_sequence_number(path, basename):
|
||||
|
||||
return result + 1
|
||||
|
||||
def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None):
|
||||
def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix=""):
|
||||
if short_filename or prompt is None or seed is None:
|
||||
file_decoration = ""
|
||||
elif opts.save_to_dirs:
|
||||
@@ -322,7 +332,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
|
||||
if file_decoration != "":
|
||||
file_decoration = "-" + file_decoration.lower()
|
||||
|
||||
file_decoration = apply_filename_pattern(file_decoration, p, seed, prompt)
|
||||
file_decoration = apply_filename_pattern(file_decoration, p, seed, prompt) + suffix
|
||||
|
||||
if extension == 'png' and opts.enable_pnginfo and info is not None:
|
||||
pnginfo = PngImagePlugin.PngInfo()
|
||||
|
||||
+5
-1
@@ -118,4 +118,8 @@ def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, pro
|
||||
|
||||
shared.total_tqdm.clear()
|
||||
|
||||
return processed.images, processed.js(), plaintext_to_html(processed.info)
|
||||
generation_info_js = processed.js()
|
||||
if opts.samples_log_stdout:
|
||||
print(generation_info_js)
|
||||
|
||||
return processed.images, generation_info_js, plaintext_to_html(processed.info)
|
||||
@@ -20,6 +20,7 @@ import modules.shared as shared
|
||||
import modules.face_restoration
|
||||
import modules.images as images
|
||||
import modules.styles
|
||||
import logging
|
||||
|
||||
|
||||
# some of those options should not be changed at all because they would break the model, so I removed them from options.
|
||||
@@ -28,11 +29,13 @@ opt_f = 8
|
||||
|
||||
|
||||
def setup_color_correction(image):
|
||||
logging.info("Calibrating color correction.")
|
||||
correction_target = cv2.cvtColor(np.asarray(image.copy()), cv2.COLOR_RGB2LAB)
|
||||
return correction_target
|
||||
|
||||
|
||||
def apply_color_correction(correction, image):
|
||||
logging.info("Applying color correction.")
|
||||
image = Image.fromarray(cv2.cvtColor(exposure.match_histograms(
|
||||
cv2.cvtColor(
|
||||
np.asarray(image),
|
||||
@@ -357,7 +360,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
|
||||
if p.restore_faces:
|
||||
if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration:
|
||||
images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p)
|
||||
images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-face-restoration")
|
||||
|
||||
devices.torch_gc()
|
||||
|
||||
@@ -366,6 +369,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
image = Image.fromarray(x_sample)
|
||||
|
||||
if p.color_corrections is not None and i < len(p.color_corrections):
|
||||
if opts.save and not p.do_not_save_samples and opts.save_images_before_color_correction:
|
||||
images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-color-correction")
|
||||
image = apply_color_correction(p.color_corrections[i], image)
|
||||
|
||||
if p.overlay_images is not None and i < len(p.overlay_images):
|
||||
@@ -457,7 +462,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
else:
|
||||
decoded_samples = self.sd_model.decode_first_stage(samples)
|
||||
|
||||
if opts.upscaler_for_hires_fix is None or opts.upscaler_for_hires_fix == "None":
|
||||
if opts.upscaler_for_img2img is None or opts.upscaler_for_img2img == "None":
|
||||
decoded_samples = torch.nn.functional.interpolate(decoded_samples, size=(self.height, self.width), mode="bilinear")
|
||||
else:
|
||||
lowres_samples = torch.clamp((decoded_samples + 1.0) / 2.0, min=0.0, max=1.0)
|
||||
@@ -467,7 +472,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2)
|
||||
x_sample = x_sample.astype(np.uint8)
|
||||
image = Image.fromarray(x_sample)
|
||||
upscaler = [x for x in shared.sd_upscalers if x.name == opts.upscaler_for_hires_fix][0]
|
||||
upscaler = [x for x in shared.sd_upscalers if x.name == opts.upscaler_for_img2img][0]
|
||||
image = upscaler.upscale(image, self.width, self.height)
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = np.moveaxis(image, 2, 0)
|
||||
|
||||
+139
-74
@@ -2,7 +2,6 @@ import sys
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from glob import glob
|
||||
import gradio as gr
|
||||
import tqdm
|
||||
|
||||
@@ -22,7 +21,7 @@ parser.add_argument("--config", type=str, default=os.path.join(sd_path, "configs
|
||||
parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; this checkpoint will be added to the list of checkpoints and loaded by default if you don't have a checkpoint selected in settings",)
|
||||
parser.add_argument("--ckpt-dir", type=str, default=os.path.join(script_path, 'models'), help="path to directory with stable diffusion checkpoints",)
|
||||
parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN'))
|
||||
parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=next(iter(glob('GFPGAN*.pth')), ''))
|
||||
parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None)
|
||||
parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats")
|
||||
parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)")
|
||||
parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI")
|
||||
@@ -100,80 +99,127 @@ def realesrgan_models_names():
|
||||
return [x.name for x in modules.realesrgan_model.get_realesrgan_models()]
|
||||
|
||||
|
||||
class Options:
|
||||
class OptionInfo:
|
||||
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None):
|
||||
self.default = default
|
||||
self.label = label
|
||||
self.component = component
|
||||
self.component_args = component_args
|
||||
self.onchange = onchange
|
||||
class OptionInfo:
|
||||
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None):
|
||||
self.default = default
|
||||
self.label = label
|
||||
self.component = component
|
||||
self.component_args = component_args
|
||||
self.onchange = onchange
|
||||
self.section = None
|
||||
|
||||
|
||||
def options_section(section_identifer, options_dict):
|
||||
for k, v in options_dict.items():
|
||||
v.section = section_identifer
|
||||
|
||||
return options_dict
|
||||
|
||||
|
||||
hide_dirs = {"visible": False} if cmd_opts.hide_ui_dir_config else None
|
||||
|
||||
options_templates = {}
|
||||
|
||||
options_templates.update(options_section(('saving-images', "Saving images/grids"), {
|
||||
"samples_save": OptionInfo(True, "Always save all generated images"),
|
||||
"samples_format": OptionInfo('png', 'File format for images'),
|
||||
"samples_filename_pattern": OptionInfo("", "Images filename pattern"),
|
||||
|
||||
"grid_save": OptionInfo(True, "Always save all generated image grids"),
|
||||
"grid_format": OptionInfo('png', 'File format for grids'),
|
||||
"grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"),
|
||||
"grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"),
|
||||
"n_rows": OptionInfo(-1, "Grid row count; use -1 for autodetect and 0 for it to be same as batch size", gr.Slider, {"minimum": -1, "maximum": 16, "step": 1}),
|
||||
|
||||
"enable_pnginfo": OptionInfo(True, "Save text information about generation parameters as chunks to png files"),
|
||||
"save_txt": OptionInfo(False, "Create a text file next to every image with generation parameters."),
|
||||
"save_images_before_face_restoration": OptionInfo(False, "Save a copy of image before doing face restoration."),
|
||||
"jpeg_quality": OptionInfo(80, "Quality for saved jpeg images", gr.Slider, {"minimum": 1, "maximum": 100, "step": 1}),
|
||||
"export_for_4chan": OptionInfo(True, "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG"),
|
||||
|
||||
"use_original_name_batch": OptionInfo(False, "Use original name for output filename during batch process in extras tab"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('saving-paths', "Paths for saving"), {
|
||||
"outdir_samples": OptionInfo("", "Output directory for images; if empty, defaults to three directories below", component_args=hide_dirs),
|
||||
"outdir_txt2img_samples": OptionInfo("outputs/txt2img-images", 'Output directory for txt2img images', component_args=hide_dirs),
|
||||
"outdir_img2img_samples": OptionInfo("outputs/img2img-images", 'Output directory for img2img images', component_args=hide_dirs),
|
||||
"outdir_extras_samples": OptionInfo("outputs/extras-images", 'Output directory for images from extras tab', component_args=hide_dirs),
|
||||
"outdir_grids": OptionInfo("", "Output directory for grids; if empty, defaults to two directories below", component_args=hide_dirs),
|
||||
"outdir_txt2img_grids": OptionInfo("outputs/txt2img-grids", 'Output directory for txt2img grids', component_args=hide_dirs),
|
||||
"outdir_img2img_grids": OptionInfo("outputs/img2img-grids", 'Output directory for img2img grids', component_args=hide_dirs),
|
||||
"outdir_save": OptionInfo("log/images", "Directory for saving images using the Save button", component_args=hide_dirs),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('saving-to-dirs', "Saving to a directory"), {
|
||||
"save_to_dirs": OptionInfo(False, "Save images to a subdirectory"),
|
||||
"grid_save_to_dirs": OptionInfo(False, "Save grids to subdirectory"),
|
||||
"directories_filename_pattern": OptionInfo("", "Directory name pattern"),
|
||||
"directories_max_prompt_words": OptionInfo(8, "Max prompt words", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers. 0 = no tiling.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"realesrgan_enabled_models": OptionInfo(["Real-ESRGAN 4x plus", "Real-ESRGAN 4x plus anime 6B"], "Select which RealESRGAN models to show in the web UI. (Requires restart)", gr.CheckboxGroup, lambda: {"choices": realesrgan_models_names()}),
|
||||
"SWIN_tile": OptionInfo(192, "Tile size for all SwinIR.", gr.Slider, {"minimum": 16, "maximum": 512, "step": 16}),
|
||||
"SWIN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SwinIR. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"ldsr_steps": OptionInfo(100, "LDSR processing steps. Lower = faster", gr.Slider, {"minimum": 1, "maximum": 200, "step": 1}),
|
||||
"ldsr_pre_down": OptionInfo(1, "LDSR Pre-process downssample scale. 1 = no down-sampling, 4 = 1/4 scale.", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}),
|
||||
"ldsr_post_down": OptionInfo(1, "LDSR Post-process down-sample scale. 1 = no down-sampling, 4 = 1/4 scale.", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}),
|
||||
|
||||
"upscaler_for_img2img": OptionInfo(None, "Upscaler for img2img", gr.Radio, lambda: {"choices": [x.name for x in sd_upscalers]}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('face-restoration', "Face restoration"), {
|
||||
"face_restoration_model": OptionInfo(None, "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}),
|
||||
"code_former_weight": OptionInfo(0.5, "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
|
||||
"face_restoration_unload": OptionInfo(False, "Move face restoration model from VRAM into RAM after processing"),
|
||||
"save_selected_only": OptionInfo(False, "When using 'Save' button, only save a single selected image"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('system', "System"), {
|
||||
"memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}),
|
||||
"samples_log_stdout": OptionInfo(False, "Always print all generation info to standard output"),
|
||||
"multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job. Broken in PyCharm console."),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Radio, lambda: {"choices": [x.title for x in modules.sd_models.checkpoints_list.values()]}),
|
||||
"img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."),
|
||||
"save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"),
|
||||
"img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."),
|
||||
"enable_quantization": OptionInfo(False, "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply."),
|
||||
"enable_emphasis": OptionInfo(True, "Use (text) to make model pay more attention to text and [text] to make it pay less attention"),
|
||||
"enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"),
|
||||
"filter_nsfw": OptionInfo(False, "Filter NSFW content"),
|
||||
"random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('interrogate', "Interrogate Options"), {
|
||||
"interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"),
|
||||
"interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"),
|
||||
"interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}),
|
||||
"interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}),
|
||||
"interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}),
|
||||
"interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('ui', "User interface"), {
|
||||
"show_progressbar": OptionInfo(True, "Show progressbar"),
|
||||
"show_progress_every_n_steps": OptionInfo(0, "Show show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}),
|
||||
"return_grid": OptionInfo(True, "Show grid in results for web"),
|
||||
"add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"),
|
||||
"font": OptionInfo("", "Font for image grids that have text"),
|
||||
"js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"),
|
||||
"js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"),
|
||||
}))
|
||||
|
||||
|
||||
class Options:
|
||||
data = None
|
||||
hide_dirs = {"visible": False} if cmd_opts.hide_ui_dir_config else None
|
||||
data_labels = {
|
||||
"samples_filename_pattern": OptionInfo("", "Images filename pattern"),
|
||||
"save_to_dirs": OptionInfo(False, "Save images to a subdirectory"),
|
||||
"grid_save_to_dirs": OptionInfo(False, "Save grids to subdirectory"),
|
||||
"directories_filename_pattern": OptionInfo("", "Directory name pattern"),
|
||||
"outdir_samples": OptionInfo("", "Output directory for images; if empty, defaults to two directories below", component_args=hide_dirs),
|
||||
"outdir_txt2img_samples": OptionInfo("outputs/txt2img-images", 'Output directory for txt2img images', component_args=hide_dirs),
|
||||
"outdir_img2img_samples": OptionInfo("outputs/img2img-images", 'Output directory for img2img images', component_args=hide_dirs),
|
||||
"outdir_extras_samples": OptionInfo("outputs/extras-images", 'Output directory for images from extras tab', component_args=hide_dirs),
|
||||
"outdir_grids": OptionInfo("", "Output directory for grids; if empty, defaults to two directories below", component_args=hide_dirs),
|
||||
"outdir_txt2img_grids": OptionInfo("outputs/txt2img-grids", 'Output directory for txt2img grids', component_args=hide_dirs),
|
||||
"outdir_img2img_grids": OptionInfo("outputs/img2img-grids", 'Output directory for img2img grids', component_args=hide_dirs),
|
||||
"outdir_save": OptionInfo("log/images", "Directory for saving images using the Save button", component_args=hide_dirs),
|
||||
"samples_save": OptionInfo(True, "Always save all generated images"),
|
||||
"save_selected_only": OptionInfo(False, "When using 'Save' button, only save a single selected image"),
|
||||
"samples_format": OptionInfo('png', 'File format for individual samples'),
|
||||
"filter_nsfw": OptionInfo(False, "Filter NSFW content"),
|
||||
"grid_save": OptionInfo(True, "Always save all generated image grids"),
|
||||
"return_grid": OptionInfo(True, "Show grid in results for web"),
|
||||
"grid_format": OptionInfo('png', 'File format for grids'),
|
||||
"grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"),
|
||||
"grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"),
|
||||
"n_rows": OptionInfo(-1, "Grid row count; use -1 for autodetect and 0 for it to be same as batch size", gr.Slider, {"minimum": -1, "maximum": 16, "step": 1}),
|
||||
"jpeg_quality": OptionInfo(80, "Quality for saved jpeg images", gr.Slider, {"minimum": 1, "maximum": 100, "step": 1}),
|
||||
"export_for_4chan": OptionInfo(True, "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG"),
|
||||
"enable_pnginfo": OptionInfo(True, "Save text information about generation parameters as chunks to png files"),
|
||||
"add_model_hash_to_info": OptionInfo(False, "Add model hash to generation information"),
|
||||
"img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."),
|
||||
"img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."),
|
||||
"enable_quantization": OptionInfo(False, "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply."),
|
||||
"font": OptionInfo("", "Font for image grids that have text"),
|
||||
"enable_emphasis": OptionInfo(True, "Use (text) to make model pay more attention to text and [text] to make it pay less attention"),
|
||||
"enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"),
|
||||
"save_txt": OptionInfo(False, "Create a text file next to every image with generation parameters."),
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers. 0 = no tiling.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"realesrgan_enabled_models": OptionInfo(["Real-ESRGAN 4x plus", "Real-ESRGAN 4x plus anime 6B"], "Select which RealESRGAN models to show in the web UI. (Requires restart)", gr.CheckboxGroup, lambda: {"choices": realesrgan_models_names()}),
|
||||
"SWIN_tile": OptionInfo(192, "Tile size for all SwinIR.", gr.Slider, {"minimum": 16, "maximum": 512, "step": 16}),
|
||||
"SWIN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SwinIR. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"ldsr_steps": OptionInfo(100, "LDSR processing steps. Lower = faster", gr.Slider, {"minimum": 1, "maximum": 200, "step": 1}),
|
||||
"ldsr_pre_down":OptionInfo(1, "LDSR Pre-process downssample scale. 1 = no down-sampling, 4 = 1/4 scale.", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}),
|
||||
"ldsr_post_down":OptionInfo(1, "LDSR Post-process down-sample scale. 1 = no down-sampling, 4 = 1/4 scale.", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}),
|
||||
"random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}),
|
||||
"upscaler_for_hires_fix": OptionInfo(None, "Upscaler for highres. fix", gr.Radio, lambda: {"choices": [x.name for x in sd_upscalers]}),
|
||||
"show_progressbar": OptionInfo(True, "Show progressbar"),
|
||||
"show_progress_every_n_steps": OptionInfo(0, "Show show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}),
|
||||
"multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job. Broken in PyCharm console."),
|
||||
"memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step":1}),
|
||||
"face_restoration_model": OptionInfo(None, "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}),
|
||||
"code_former_weight": OptionInfo(0.5, "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
|
||||
"save_images_before_face_restoration": OptionInfo(False, "Save a copy of image before doing face restoration."),
|
||||
"face_restoration_unload": OptionInfo(False, "Move face restoration model from VRAM into RAM after processing"),
|
||||
"interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"),
|
||||
"interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"),
|
||||
"interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}),
|
||||
"interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}),
|
||||
"interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}),
|
||||
"interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)"),
|
||||
"sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Radio, lambda: {"choices": [x.title for x in modules.sd_models.checkpoints_list.values()]}),
|
||||
"js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"),
|
||||
"js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"),
|
||||
"use_original_name_batch": OptionInfo(False, "Use original name for output filename during batch process"),
|
||||
}
|
||||
data_labels = options_templates
|
||||
typemap = {int: float}
|
||||
|
||||
def __init__(self):
|
||||
self.data = {k: v.default for k, v in self.data_labels.items()}
|
||||
@@ -199,10 +245,29 @@ class Options:
|
||||
with open(filename, "w", encoding="utf8") as file:
|
||||
json.dump(self.data, file)
|
||||
|
||||
def same_type(self, x, y):
|
||||
if x is None or y is None:
|
||||
return True
|
||||
|
||||
type_x = self.typemap.get(type(x), type(x))
|
||||
type_y = self.typemap.get(type(y), type(y))
|
||||
|
||||
return type_x == type_y
|
||||
|
||||
def load(self, filename):
|
||||
with open(filename, "r", encoding="utf8") as file:
|
||||
self.data = json.load(file)
|
||||
|
||||
bad_settings = 0
|
||||
for k, v in self.data.items():
|
||||
info = self.data_labels.get(k, None)
|
||||
if info is not None and not self.same_type(info.default, v):
|
||||
print(f"Warning: bad setting value: {k}: {v} ({type(v).__name__}; expected {type(info.default).__name__})", file=sys.stderr)
|
||||
bad_settings += 1
|
||||
|
||||
if bad_settings > 0:
|
||||
print(f"The program is likely to not work with bad settings.\nSettings file: {filename}\nEither fix the file, or delete it and restart.", file=sys.stderr)
|
||||
|
||||
def onchange(self, key, func):
|
||||
item = self.data_labels.get(key)
|
||||
item.onchange = func
|
||||
|
||||
+6
-4
@@ -37,12 +37,14 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2:
|
||||
print(f"\ntxt2img: {prompt}", file=shared.progress_print_out)
|
||||
processed = modules.scripts.scripts_txt2img.run(p, *args)
|
||||
|
||||
if processed is not None:
|
||||
pass
|
||||
else:
|
||||
if processed is None:
|
||||
processed = process_images(p)
|
||||
|
||||
shared.total_tqdm.clear()
|
||||
|
||||
return processed.images, processed.js(), plaintext_to_html(processed.info)
|
||||
generation_info_js = processed.js()
|
||||
if opts.samples_log_stdout:
|
||||
print(generation_info_js)
|
||||
|
||||
return processed.images, generation_info_js, plaintext_to_html(processed.info)
|
||||
|
||||
|
||||
+173
-105
@@ -22,12 +22,12 @@ from modules.paths import script_path
|
||||
from modules.shared import opts, cmd_opts
|
||||
import modules.shared as shared
|
||||
from modules.sd_samplers import samplers, samplers_for_img2img
|
||||
import modules.realesrgan_model as realesrgan
|
||||
import modules.ldsr_model
|
||||
import modules.scripts
|
||||
import modules.gfpgan_model
|
||||
import modules.codeformer_model
|
||||
import modules.styles
|
||||
import modules.generation_parameters_copypaste
|
||||
|
||||
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI
|
||||
mimetypes.init()
|
||||
@@ -58,6 +58,8 @@ css_hide_progressbar = """
|
||||
# Important that they exactly match script.js for tooltip to work.
|
||||
random_symbol = '\U0001f3b2\ufe0f' # 🎲️
|
||||
reuse_symbol = '\u267b\ufe0f' # ♻️
|
||||
art_symbol = '\U0001f3a8' # 🎨
|
||||
paste_symbol = '\u2199\ufe0f' # ↙
|
||||
|
||||
|
||||
def plaintext_to_html(text):
|
||||
@@ -167,7 +169,7 @@ def wrap_gradio_call(func):
|
||||
return f
|
||||
|
||||
|
||||
def check_progress_call():
|
||||
def check_progress_call(id_part):
|
||||
if shared.state.job_count == 0:
|
||||
return "", gr_show(False), gr_show(False)
|
||||
|
||||
@@ -201,15 +203,15 @@ def check_progress_call():
|
||||
else:
|
||||
preview_visibility = gr_show(True)
|
||||
|
||||
return f"<span style='display: none'>{time.time()}</span><p>{progressbar}</p>", preview_visibility, image
|
||||
return f"<span id='{id_part}_progress_span' style='display: none'>{time.time()}</span><p>{progressbar}</p>", preview_visibility, image
|
||||
|
||||
|
||||
def check_progress_call_initial():
|
||||
def check_progress_call_initial(id_part):
|
||||
shared.state.job_count = -1
|
||||
shared.state.current_latent = None
|
||||
shared.state.current_image = None
|
||||
|
||||
return check_progress_call()
|
||||
return check_progress_call(id_part)
|
||||
|
||||
|
||||
def roll_artist(prompt):
|
||||
@@ -237,8 +239,7 @@ def add_style(name: str, prompt: str, negative_prompt: str):
|
||||
# reserialize all styles every time we save them
|
||||
shared.prompt_styles.save_styles(shared.styles_filename)
|
||||
|
||||
update = {"visible": True, "choices": list(shared.prompt_styles.styles), "__type__": "update"}
|
||||
return [update, update, update, update]
|
||||
return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)]
|
||||
|
||||
|
||||
def apply_styles(prompt, prompt_neg, style1_name, style2_name):
|
||||
@@ -330,27 +331,32 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info:
|
||||
|
||||
|
||||
def create_toprow(is_img2img):
|
||||
id_part = "img2img" if is_img2img else "txt2img"
|
||||
|
||||
with gr.Row(elem_id="toprow"):
|
||||
with gr.Column(scale=4):
|
||||
with gr.Row():
|
||||
with gr.Column(scale=8):
|
||||
with gr.Column(scale=80):
|
||||
with gr.Row():
|
||||
prompt = gr.Textbox(label="Prompt", elem_id="prompt", show_label=False, placeholder="Prompt", lines=2)
|
||||
roll = gr.Button('Roll', elem_id="roll", visible=len(shared.artist_db.artists) > 0)
|
||||
|
||||
with gr.Column(scale=1, elem_id="style_pos_col"):
|
||||
prompt_style = gr.Dropdown(label="Style 1", elem_id="style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1)
|
||||
with gr.Column(scale=1, elem_id="roll_col"):
|
||||
roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0)
|
||||
paste = gr.Button(value=paste_symbol, elem_id="paste")
|
||||
|
||||
with gr.Column(scale=10, elem_id="style_pos_col"):
|
||||
prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1)
|
||||
|
||||
with gr.Row():
|
||||
with gr.Column(scale=8):
|
||||
negative_prompt = gr.Textbox(label="Negative prompt", elem_id="negative_prompt", show_label=False, placeholder="Negative prompt", lines=2)
|
||||
|
||||
with gr.Column(scale=1, elem_id="style_neg_col"):
|
||||
prompt_style2 = gr.Dropdown(label="Style 2", elem_id="style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1)
|
||||
prompt_style2 = gr.Dropdown(label="Style 2", elem_id=f"{id_part}_style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1)
|
||||
|
||||
with gr.Column(scale=1):
|
||||
with gr.Row():
|
||||
interrupt = gr.Button('Interrupt', elem_id="interrupt")
|
||||
interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt")
|
||||
submit = gr.Button('Generate', elem_id="generate", variant='primary')
|
||||
|
||||
interrupt.click(
|
||||
@@ -367,21 +373,21 @@ def create_toprow(is_img2img):
|
||||
prompt_style_apply = gr.Button('Apply style', elem_id="style_apply")
|
||||
save_style = gr.Button('Create style', elem_id="style_create")
|
||||
|
||||
return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style
|
||||
return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste
|
||||
|
||||
|
||||
def setup_progressbar(progressbar, preview):
|
||||
check_progress = gr.Button('Check progress', elem_id="check_progress", visible=False)
|
||||
def setup_progressbar(progressbar, preview, id_part):
|
||||
check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False)
|
||||
check_progress.click(
|
||||
fn=check_progress_call,
|
||||
fn=lambda: check_progress_call(id_part),
|
||||
show_progress=False,
|
||||
inputs=[],
|
||||
outputs=[progressbar, preview, preview],
|
||||
)
|
||||
|
||||
check_progress_initial = gr.Button('Check progress (first)', elem_id="check_progress_initial", visible=False)
|
||||
check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False)
|
||||
check_progress_initial.click(
|
||||
fn=check_progress_call_initial,
|
||||
fn=lambda: check_progress_call_initial(id_part),
|
||||
show_progress=False,
|
||||
inputs=[],
|
||||
outputs=[progressbar, preview, preview],
|
||||
@@ -390,17 +396,17 @@ def setup_progressbar(progressbar, preview):
|
||||
|
||||
def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
||||
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style = create_toprow(is_img2img=False)
|
||||
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste = create_toprow(is_img2img=False)
|
||||
dummy_component = gr.Label(visible=False)
|
||||
|
||||
with gr.Row(elem_id='progressRow'):
|
||||
with gr.Column(scale=1):
|
||||
columnEmpty = "Empty"
|
||||
with gr.Row(elem_id='txt2img_progress_row'):
|
||||
with gr.Column(scale=1):
|
||||
pass
|
||||
|
||||
with gr.Column(scale=1):
|
||||
progressbar = gr.HTML(elem_id="progressbar")
|
||||
with gr.Column(scale=1):
|
||||
progressbar = gr.HTML(elem_id="txt2img_progressbar")
|
||||
txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
|
||||
setup_progressbar(progressbar, txt2img_preview)
|
||||
setup_progressbar(progressbar, txt2img_preview, 'txt2img')
|
||||
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
@@ -435,7 +441,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
|
||||
with gr.Group():
|
||||
txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
|
||||
txt2img_gallery = gr.Gallery(label='Output', elem_id='txt2img_gallery').style(grid=4)
|
||||
txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4)
|
||||
|
||||
with gr.Group():
|
||||
with gr.Row():
|
||||
@@ -516,28 +522,46 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
]
|
||||
)
|
||||
|
||||
txt2img_paste_fields = {
|
||||
"Prompt": txt2img_prompt,
|
||||
"Negative prompt": txt2img_negative_prompt,
|
||||
"Steps": steps,
|
||||
"Sampler": sampler_index,
|
||||
"Face restoration": restore_faces,
|
||||
"CFG scale": cfg_scale,
|
||||
"Seed": seed,
|
||||
"Size-1": width,
|
||||
"Size-2": height,
|
||||
"Batch size": batch_size,
|
||||
"Variation seed": subseed,
|
||||
"Variation seed strength": subseed_strength,
|
||||
"Seed resize from-1": seed_resize_from_w,
|
||||
"Seed resize from-2": seed_resize_from_h,
|
||||
"Denoising strength": denoising_strength,
|
||||
}
|
||||
modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt)
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as img2img_interface:
|
||||
img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style = create_toprow(is_img2img=True)
|
||||
img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste = create_toprow(is_img2img=True)
|
||||
|
||||
with gr.Row(elem_id='progressRow'):
|
||||
with gr.Column(scale=1):
|
||||
columnEmpty = "Empty"
|
||||
with gr.Row(elem_id='img2img_progress_row'):
|
||||
with gr.Column(scale=1):
|
||||
pass
|
||||
|
||||
with gr.Column(scale=1):
|
||||
progressbar = gr.HTML(elem_id="progressbar")
|
||||
with gr.Column(scale=1):
|
||||
progressbar = gr.HTML(elem_id="img2img_progressbar")
|
||||
img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
|
||||
setup_progressbar(progressbar, img2img_preview)
|
||||
setup_progressbar(progressbar, img2img_preview, 'img2img')
|
||||
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
|
||||
with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
|
||||
with gr.TabItem('img2img'):
|
||||
with gr.TabItem('img2img', id='img2img'):
|
||||
init_img = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.TabItem('Inpaint'):
|
||||
with gr.TabItem('Inpaint', id='inpaint'):
|
||||
init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA")
|
||||
init_img_with_mask_comment = gr.HTML(elem_id="mask_bug_info", value="<small>if the editor shows ERROR, switch to another tab and back, then to \"Upload mask\" mode above and back</small>")
|
||||
|
||||
init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", visible=False)
|
||||
init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", visible=False)
|
||||
@@ -554,7 +578,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=False)
|
||||
inpaint_full_res_padding = gr.Slider(label='Inpaint at full resolution padding, pixels', minimum=0, maximum=256, step=4, value=32)
|
||||
|
||||
with gr.TabItem('Batch img2img'):
|
||||
with gr.TabItem('Batch img2img', id='batch'):
|
||||
gr.HTML("<p class=\"text-gray-500\">Process images in a directory on the same machine where the server is running.</p>")
|
||||
img2img_batch_input_dir = gr.Textbox(label="Input directory")
|
||||
img2img_batch_output_dir = gr.Textbox(label="Output directory")
|
||||
@@ -590,7 +614,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
|
||||
with gr.Group():
|
||||
img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
|
||||
img2img_gallery = gr.Gallery(label='Output', elem_id='img2img_gallery').style(grid=4)
|
||||
img2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='img2img_gallery').style(grid=4)
|
||||
|
||||
with gr.Group():
|
||||
with gr.Row():
|
||||
@@ -598,7 +622,6 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
img2img_send_to_img2img = gr.Button('Send to img2img')
|
||||
img2img_send_to_inpaint = gr.Button('Send to inpaint')
|
||||
img2img_send_to_extras = gr.Button('Send to extras')
|
||||
img2img_save_style = gr.Button('Save prompt as style')
|
||||
|
||||
with gr.Group():
|
||||
html_info = gr.HTML()
|
||||
@@ -609,16 +632,13 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
|
||||
mask_mode.change(
|
||||
lambda mode, img: {
|
||||
#init_img_with_mask: gr.Image.update(visible=mode == 0, value=img["image"]),
|
||||
init_img_with_mask: gr_show(mode == 0),
|
||||
init_img_with_mask_comment: gr_show(mode == 0),
|
||||
init_img_inpaint: gr_show(mode == 1),
|
||||
init_mask_inpaint: gr_show(mode == 1),
|
||||
},
|
||||
inputs=[mask_mode, init_img_with_mask],
|
||||
outputs=[
|
||||
init_img_with_mask,
|
||||
init_img_with_mask_comment,
|
||||
init_img_inpaint,
|
||||
init_mask_inpaint,
|
||||
],
|
||||
@@ -721,12 +741,31 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
outputs=[prompt, negative_prompt, style1, style2],
|
||||
)
|
||||
|
||||
img2img_paste_fields = {
|
||||
"Prompt": img2img_prompt,
|
||||
"Negative prompt": img2img_negative_prompt,
|
||||
"Steps": steps,
|
||||
"Sampler": sampler_index,
|
||||
"Face restoration": restore_faces,
|
||||
"CFG scale": cfg_scale,
|
||||
"Seed": seed,
|
||||
"Size-1": width,
|
||||
"Size-2": height,
|
||||
"Batch size": batch_size,
|
||||
"Variation seed": subseed,
|
||||
"Variation seed strength": subseed_strength,
|
||||
"Seed resize from-1": seed_resize_from_w,
|
||||
"Seed resize from-2": seed_resize_from_h,
|
||||
"Denoising strength": denoising_strength,
|
||||
}
|
||||
modules.generation_parameters_copypaste.connect_paste(paste, img2img_paste_fields, img2img_prompt)
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
with gr.Tabs(elem_id="mode_extras"):
|
||||
with gr.TabItem('Single Image'):
|
||||
image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
|
||||
extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.TabItem('Batch Process'):
|
||||
image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file")
|
||||
@@ -750,16 +789,18 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
submit = gr.Button('Generate', elem_id="extras_generate", variant='primary')
|
||||
|
||||
with gr.Column(variant='panel'):
|
||||
result_images = gr.Gallery(label="Result")
|
||||
result_images = gr.Gallery(label="Result", show_label=False)
|
||||
html_info_x = gr.HTML()
|
||||
html_info = gr.HTML()
|
||||
extras_send_to_img2img = gr.Button('Send to img2img')
|
||||
extras_send_to_inpaint = gr.Button('Send to inpaint')
|
||||
|
||||
submit.click(
|
||||
fn=run_extras,
|
||||
_js="get_extras_tab_index",
|
||||
inputs=[
|
||||
dummy_component,
|
||||
image,
|
||||
extras_image,
|
||||
image_batch,
|
||||
gfpgan_visibility,
|
||||
codeformer_visibility,
|
||||
@@ -775,21 +816,40 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
html_info,
|
||||
]
|
||||
)
|
||||
|
||||
extras_send_to_img2img.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[result_images],
|
||||
outputs=[init_img],
|
||||
)
|
||||
|
||||
extras_send_to_inpaint.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[result_images],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
||||
pnginfo_interface = gr.Interface(
|
||||
wrap_gradio_call(run_pnginfo),
|
||||
inputs=[
|
||||
gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil"),
|
||||
],
|
||||
outputs=[
|
||||
gr.HTML(),
|
||||
gr.HTML(),
|
||||
gr.HTML(),
|
||||
],
|
||||
allow_flagging="never",
|
||||
analytics_enabled=False,
|
||||
live=True,
|
||||
)
|
||||
with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.Column(variant='panel'):
|
||||
html = gr.HTML()
|
||||
generation_info = gr.Textbox(visible=False)
|
||||
html2 = gr.HTML()
|
||||
|
||||
with gr.Row():
|
||||
pnginfo_send_to_txt2img = gr.Button('Send to txt2img')
|
||||
pnginfo_send_to_img2img = gr.Button('Send to img2img')
|
||||
|
||||
image.change(
|
||||
fn=wrap_gradio_call(run_pnginfo),
|
||||
inputs=[image],
|
||||
outputs=[html, generation_info, html2],
|
||||
)
|
||||
|
||||
def create_setting_component(key):
|
||||
def fun():
|
||||
@@ -814,12 +874,13 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
return comp(label=info.label, value=fun, **(args or {}))
|
||||
|
||||
components = []
|
||||
keys = list(opts.data_labels.keys())
|
||||
settings_cols = 3
|
||||
items_per_col = math.ceil(len(keys) / settings_cols)
|
||||
|
||||
def run_settings(*args):
|
||||
up = []
|
||||
changed = 0
|
||||
|
||||
for key, value, comp in zip(opts.data_labels.keys(), args, components):
|
||||
if not opts.same_type(value, opts.data_labels[key].default):
|
||||
return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}"
|
||||
|
||||
for key, value, comp in zip(opts.data_labels.keys(), args, components):
|
||||
comp_args = opts.data_labels[key].component_args
|
||||
@@ -829,42 +890,59 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
oldval = opts.data.get(key, None)
|
||||
opts.data[key] = value
|
||||
|
||||
if oldval != value and opts.data_labels[key].onchange is not None:
|
||||
opts.data_labels[key].onchange()
|
||||
if oldval != value:
|
||||
if opts.data_labels[key].onchange is not None:
|
||||
opts.data_labels[key].onchange()
|
||||
|
||||
up.append(comp.update(value=value))
|
||||
changed += 1
|
||||
|
||||
opts.save(shared.config_filename)
|
||||
|
||||
return 'Settings applied.'
|
||||
return f'{changed} settings changed.', opts.dumpjson()
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as settings_interface:
|
||||
settings_submit = gr.Button(value="Apply settings", variant='primary')
|
||||
result = gr.HTML()
|
||||
|
||||
settings_cols = 3
|
||||
items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols)
|
||||
|
||||
cols_displayed = 0
|
||||
items_displayed = 0
|
||||
previous_section = None
|
||||
column = None
|
||||
with gr.Row(elem_id="settings").style(equal_height=False):
|
||||
for colno in range(settings_cols):
|
||||
with gr.Column(variant='panel'):
|
||||
for rowno in range(items_per_col):
|
||||
index = rowno + colno * items_per_col
|
||||
for i, (k, item) in enumerate(opts.data_labels.items()):
|
||||
|
||||
if index < len(keys):
|
||||
components.append(create_setting_component(keys[index]))
|
||||
if previous_section != item.section:
|
||||
if cols_displayed < settings_cols and (items_displayed >= items_per_col or previous_section is None):
|
||||
if column is not None:
|
||||
column.__exit__()
|
||||
|
||||
settings_submit.click(
|
||||
fn=run_settings,
|
||||
inputs=components,
|
||||
outputs=[result]
|
||||
)
|
||||
column = gr.Column(variant='panel')
|
||||
column.__enter__()
|
||||
|
||||
request_notifications = gr.Button(value='Request browser notifications')
|
||||
items_displayed = 0
|
||||
cols_displayed += 1
|
||||
|
||||
previous_section = item.section
|
||||
|
||||
gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='<h1 class="gr-button-lg">{}</h1>'.format(item.section[1]))
|
||||
|
||||
components.append(create_setting_component(k))
|
||||
items_displayed += 1
|
||||
|
||||
request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
|
||||
request_notifications.click(
|
||||
fn=lambda: None,
|
||||
inputs=[],
|
||||
outputs=[],
|
||||
_js='() => Notification.requestPermission()'
|
||||
_js='function(){}'
|
||||
)
|
||||
|
||||
if column is not None:
|
||||
column.__exit__()
|
||||
|
||||
interfaces = [
|
||||
(txt2img_interface, "txt2img", "txt2img"),
|
||||
(img2img_interface, "img2img", "img2img"),
|
||||
@@ -892,49 +970,36 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
interface.render()
|
||||
|
||||
text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
|
||||
|
||||
settings_submit.click(
|
||||
fn=lambda: opts.dumpjson(),
|
||||
inputs=[],
|
||||
outputs=[text_settings],
|
||||
)
|
||||
|
||||
tabs.change(
|
||||
fn=lambda x: x,
|
||||
inputs=[init_img_with_mask],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
||||
tabs_img2img_mode.change(
|
||||
fn=lambda x: x,
|
||||
inputs=[init_img_with_mask],
|
||||
outputs=[init_img_with_mask],
|
||||
fn=run_settings,
|
||||
inputs=components,
|
||||
outputs=[result, text_settings],
|
||||
)
|
||||
|
||||
send_to_img2img.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
fn=lambda x: (image_from_url_text(x)),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[init_img],
|
||||
)
|
||||
|
||||
send_to_inpaint.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
fn=lambda x: (image_from_url_text(x)),
|
||||
_js="extract_image_from_gallery_inpaint",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
||||
img2img_send_to_img2img.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery",
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[init_img],
|
||||
)
|
||||
|
||||
img2img_send_to_inpaint.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery",
|
||||
_js="extract_image_from_gallery_inpaint",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
@@ -943,16 +1008,19 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_extras",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[image],
|
||||
outputs=[extras_image],
|
||||
)
|
||||
|
||||
img2img_send_to_extras.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_extras",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[image],
|
||||
outputs=[extras_image],
|
||||
)
|
||||
|
||||
modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields, generation_info, 'switch_to_txt2img')
|
||||
modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields, generation_info, 'switch_to_img2img_img2img')
|
||||
|
||||
ui_config_file = cmd_opts.ui_config_file
|
||||
ui_settings = {}
|
||||
settings_count = len(ui_settings)
|
||||
@@ -1001,7 +1069,7 @@ with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfil
|
||||
javascript = f'<script>{jsfile.read()}</script>'
|
||||
|
||||
jsdir = os.path.join(script_path, "javascript")
|
||||
for filename in os.listdir(jsdir):
|
||||
for filename in sorted(os.listdir(jsdir)):
|
||||
with open(os.path.join(jsdir, filename), "r", encoding="utf8") as jsfile:
|
||||
javascript += f"\n<script>{jsfile.read()}</script>"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ transformers==4.19.2
|
||||
diffusers==0.3.0
|
||||
basicsr==1.4.2
|
||||
gfpgan==1.3.8
|
||||
gradio==3.3.1
|
||||
gradio==3.4b3
|
||||
numpy==1.23.3
|
||||
Pillow==9.2.0
|
||||
realesrgan==0.3.0
|
||||
|
||||
@@ -2,24 +2,40 @@ function gradioApp(){
|
||||
return document.getElementsByTagName('gradio-app')[0].shadowRoot;
|
||||
}
|
||||
|
||||
function get_uiCurrentTab() {
|
||||
return gradioApp().querySelector('.tabs button:not(.border-transparent)')
|
||||
}
|
||||
|
||||
uiUpdateCallbacks = []
|
||||
uiTabChangeCallbacks = []
|
||||
let uiCurrentTab = null
|
||||
|
||||
function onUiUpdate(callback){
|
||||
uiUpdateCallbacks.push(callback)
|
||||
}
|
||||
function onUiTabChange(callback){
|
||||
uiTabChangeCallbacks.push(callback)
|
||||
}
|
||||
|
||||
function uiUpdate(root){
|
||||
uiUpdateCallbacks.forEach(function(x){
|
||||
try {
|
||||
x()
|
||||
} catch (e) {
|
||||
(console.error || console.log).call(console, e.message, e);
|
||||
}
|
||||
})
|
||||
function runCallback(x){
|
||||
try {
|
||||
x()
|
||||
} catch (e) {
|
||||
(console.error || console.log).call(console, e.message, e);
|
||||
}
|
||||
}
|
||||
function executeCallbacks(queue) {
|
||||
queue.forEach(runCallback)
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var mutationObserver = new MutationObserver(function(m){
|
||||
uiUpdate(gradioApp());
|
||||
executeCallbacks(uiUpdateCallbacks);
|
||||
const newTab = get_uiCurrentTab();
|
||||
if ( newTab && ( newTab !== uiCurrentTab ) ) {
|
||||
uiCurrentTab = newTab;
|
||||
executeCallbacks(uiTabChangeCallbacks);
|
||||
}
|
||||
});
|
||||
mutationObserver.observe( gradioApp(), { childList:true, subtree:true })
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ from modules import images, processing, devices
|
||||
from modules.processing import Processed, process_images
|
||||
from modules.shared import opts, cmd_opts, state
|
||||
|
||||
|
||||
# https://github.com/parlance-zz/g-diffuser-bot
|
||||
def expand(x, dir, amount, power=0.75):
|
||||
is_left = dir == 3
|
||||
is_right = dir == 1
|
||||
|
||||
@@ -74,10 +74,21 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#roll{
|
||||
min-width: 1em;
|
||||
max-width: 4em;
|
||||
margin: 0.5em;
|
||||
#roll_col{
|
||||
min-width: unset !important;
|
||||
flex-grow: 0 !important;
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
|
||||
#roll, #paste{
|
||||
min-width: 2em;
|
||||
min-height: 2em;
|
||||
max-width: 2em;
|
||||
max-height: 2em;
|
||||
flex-grow: 0;
|
||||
padding-left: 0.25em;
|
||||
padding-right: 0.25em;
|
||||
margin: 0.1em 0;
|
||||
}
|
||||
|
||||
#style_apply, #style_create, #interrogate{
|
||||
@@ -89,7 +100,7 @@
|
||||
min-width: 8em !important;
|
||||
}
|
||||
|
||||
#style_index, #style2_index{
|
||||
#txt2img_style_index, #txt2img_style2_index, #img2img_style_index, #img2img_style2_index{
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@@ -143,7 +154,23 @@ button{
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 34px;
|
||||
z-index: 100;
|
||||
border: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
#txt2img_preview, #img2img_preview {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#txt2img_preview, #img2img_preview {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
#txt2img_preview div.left-0.top-0, #img2img_preview div.left-0.top-0{
|
||||
@@ -210,7 +237,7 @@ input[type="range"]{
|
||||
#txt2img_negative_prompt, #img2img_negative_prompt{
|
||||
}
|
||||
|
||||
#progressbar{
|
||||
#txt2img_progressbar, #img2img_progressbar{
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
right: 0;
|
||||
@@ -219,7 +246,7 @@ input[type="range"]{
|
||||
display: block;
|
||||
}
|
||||
|
||||
#progressRow{
|
||||
#txt2img_progress_row, #img2img_progress_row{
|
||||
margin-bottom: 10px;
|
||||
margin-top: -18px;
|
||||
}
|
||||
@@ -354,7 +381,7 @@ input[type="range"]{
|
||||
display:none
|
||||
}
|
||||
|
||||
#interrupt{
|
||||
#txt2img_interrupt, #img2img_interrupt{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 72px;
|
||||
|
||||
Reference in New Issue
Block a user