update modernui

Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
Vladimir Mandic
2025-07-28 13:47:13 -04:00
parent b34324eeb2
commit 8ec16d5b8c
8 changed files with 25 additions and 21 deletions
+5 -4
View File
@@ -1,11 +1,11 @@
# Change Log for SD.Next
## Update for 2025-07-27
## Update for 2025-07-28
### Highlights for 2025-07-27
### Highlights for 2025-07-28
Feature highlights include:
- **ModernUI** layout redesign which should make it more user friendly and easier to navigate plus several new UI themes!
- **ModernUI** has quite some redesign which should make it more user friendly and easier to navigate plus several new UI themes!
- New models [WanAI Wan 2.1](https://wan.video/) for text-to-image workflows, [FreePix F-Lite](https://huggingface.co/Freepik/F-Lite), [Bria 3.2](https://huggingface.co/briaai/BRIA-3.2), [bigASP 2.5](https://civitai.com/models/1789765?modelVersionId=2025412)
- Redesigned [LTXVideo](https://vladmandic.github.io/sdnext-docs/Video) interface with support for general video models plus optimized [FramePack](https://vladmandic.github.io/sdnext-docs/FramePack) and [LTXVideo](https://vladmandic.github.io/sdnext-docs/LTX) support
- Fully integrated nudity detection and optional censorship with [NudeNet](https://vladmandic.github.io/sdnext-docs/NudeNet)
@@ -29,7 +29,7 @@ For details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/master
[ReadMe](https://github.com/vladmandic/automatic/blob/master/README.md) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [WiKi](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867)
### Details for 2025-07-27
### Details for 2025-07-28
- **License**
- SD.Next [license](https://github.com/vladmandic/sdnext/blob/dev/LICENSE.txt) switched from **aGPL-v3.0** to **Apache-v2.0**
@@ -127,6 +127,7 @@ For details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/master
see [docs](https://vladmandic.github.io/sdnext-docs/Detailer/) for more information
- **Detailer** add option to merge multiple results from each detailer model
for example, hands model can result in two hands each being processed separately or both hands can be merged into one composite job
- **Control** auto-update width/height on image upload
- **SDNQ**
- use inference context during quantization
- use static compile
+3 -2
View File
@@ -39,9 +39,10 @@ class GalleryFolder extends HTMLElement {
const style = document.createElement('style'); // silly but necessasry since we're inside shadowdom
if (window.opts.theme_type === 'Modern') {
style.textContent = `
.gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; background-color: var(--sd-button-normal-color); border-radius: var(--sd-border-radius); }
.gallery-folder { cursor: pointer; padding: 8px 6px 8px 6px; background-color: var(--sd-button-normal-color); border-radius: var(--sd-border-radius); text-align: left; min-width: 12em;}
.gallery-folder:hover { background-color: var(--button-primary-background-fill-hover); }
.gallery-folder-selected { background-color: var(--sd-button-selected-color); color: var(--sd-button-selected-text-color); }
.gallery-folder-icon { font-size: 1.2em; color: var(--sd-button-icon-color); margin-right: 1em; filter: drop-shadow(1px 1px 2px black); float: left; }
`;
} else {
style.textContent = `
@@ -53,7 +54,7 @@ class GalleryFolder extends HTMLElement {
this.shadow.appendChild(style);
const div = document.createElement('div');
div.className = 'gallery-folder';
div.textContent = `\uf44a ${this.name}`;
div.innerHTML = `<span class="gallery-folder-icon">\uf03e</span> ${this.name}`;
div.addEventListener('click', () => {
for (const folder of el.folders.children) {
if (folder.name === this.name) folder.shadow.children[1].classList.add('gallery-folder-selected');
+2 -2
View File
@@ -420,9 +420,9 @@ class YoloRestorer(Detailer):
with gr.Row():
classes = gr.Textbox(label="Detailer classes", placeholder="Classes", elem_id=f"{tab}_detailer_classes")
with gr.Row():
prompt = gr.Textbox(label="Detailer prompt", value='', placeholder='Detailer prompt', lines=2, elem_id=f"{tab}_detailer_prompt")
prompt = gr.Textbox(label="Detailer prompt", value='', placeholder='detailer prompt or leave empty to use main prompt', lines=2, elem_id=f"{tab}_detailer_prompt")
with gr.Row():
negative = gr.Textbox(label="Detailer negative prompt", value='', placeholder='Detailer negative prompt', lines=2, elem_id=f"{tab}_detailer_negative")
negative = gr.Textbox(label="Detailer negative prompt", value='', placeholder='detailer prompt or leave empty to use main prompt', lines=2, elem_id=f"{tab}_detailer_negative")
with gr.Row():
steps = gr.Slider(label="Detailer steps", elem_id=f"{tab}_detailer_steps", value=10, minimum=0, maximum=99, step=1)
strength = gr.Slider(label="Detailer strength", elem_id=f"{tab}_detailer_strength", value=0.3, minimum=0, maximum=1, step=0.01)
+2 -4
View File
@@ -554,13 +554,11 @@ def create_ui(_blocks: gr.Blocks=None):
btn_negative_counter.click(fn=call_queue.wrap_queued_call(ui_common.update_token_counter), inputs=[negative], outputs=[negative_counter])
btn_interrogate.click(fn=helpers.interrogate, inputs=[], outputs=[prompt])
select_fields = [input_mode, input_image, init_image, input_type, input_resize, input_inpaint, input_video, input_batch, input_folder]
select_output = [output_tabs, preview_process, result_txt]
select_dict = dict(
fn=helpers.select_input,
_js="controlInputMode",
inputs=select_fields,
outputs=select_output,
inputs=[input_mode, input_image, init_image, input_type, input_resize, input_inpaint, input_video, input_batch, input_folder],
outputs=[output_tabs, preview_process, result_txt, width_before, height_before],
show_progress=True,
queue=False,
)
+4 -2
View File
@@ -91,11 +91,12 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
selected_input = input_folder
else:
selected_input = None
size = [gr.update(), gr.update()]
if selected_input is None:
input_source = None
busy = False
# debug('Control input: none')
return [gr.Tabs.update(), None, '']
return [gr.Tabs.update(), None, ''] + size
input_type = type(selected_input)
input_mask = None
status = 'Control input | Unknown'
@@ -108,6 +109,7 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
input_source = [selected_input]
input_type = 'PIL.Image'
status = f'Control input | Image | Size {selected_input.width}x{selected_input.height} | Mode {selected_input.mode}'
size = [gr.update(value=selected_input.width), gr.update(value=selected_input.height)]
res = [gr.Tabs.update(selected='out-gallery'), input_mask, status]
elif isinstance(selected_input, dict): # inpaint -> dict image+mask
input_mask = selected_input['mask']
@@ -145,7 +147,7 @@ def select_input(input_mode, input_image, init_image, init_type, input_resize, i
input_init = [init_image]
debug_log(f'Control select input: type={input_type} source={input_source} init={input_init} mask={input_mask} mode={input_mode}')
busy = False
return res
return res + size
def copy_input(mode_from, mode_to, input_image, input_resize, input_inpaint):
+2
View File
@@ -41,6 +41,8 @@ def create_ui():
interrupt.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
skip = gr.Button('Skip', elem_id=f"{id_part}_skip", variant='secondary')
skip.click(fn=lambda: shared.state.skip(), inputs=[], outputs=[])
pause = gr.Button('Pause', elem_id=f"{id_part}_pause")
pause.click(fn=lambda: shared.state.pause(), _js='checkPaused', inputs=[], outputs=[])
result_images, generation_info, html_info, html_info_formatted, html_log = ui_common.create_output_panel("extras")
gr.HTML('File metadata')
exif_info = gr.HTML(elem_id="pnginfo_html_info")
+6 -6
View File
@@ -323,15 +323,15 @@ def create_hires_inputs(tab):
with gr.Row(elem_id=f"{tab}_refiner_row1"):
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Refiner start', value=0.0, elem_id=f"{tab}_refiner_start")
refiner_steps = gr.Slider(minimum=0, maximum=99, step=1, label="Refiner steps", elem_id=f"{tab}_refiner_steps", value=20)
refiner_prompt = gr.Textbox(value='', lines=2, label='Refine prompt', elem_id=f"{tab}_refiner_prompt", elem_classes=["prompt"])
refiner_negative = gr.Textbox(value='', lines=2, label='Refine negative prompt', elem_id=f"{tab}_refiner_neg_prompt", elem_classes=["prompt"])
refiner_prompt = gr.Textbox(value='', lines=2, label='Refine prompt', elem_id=f"{tab}_refiner_prompt", elem_classes=["prompt"], placeholder="refine prompt or leave empty to use main prompt")
refiner_negative = gr.Textbox(value='', lines=2, label='Refine negative prompt', elem_id=f"{tab}_refiner_neg_prompt", elem_classes=["prompt"], placeholder="refine negative prompt or leave empty to use main prompt")
return enable_hr, hr_sampler_index, denoising_strength, hr_resize_mode, hr_resize_context, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative
def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=True, prefix=''):
dummy_component = gr.Number(visible=False, value=0)
if len(prefix) > 0 and not prefix.startswith(' '):
prefix = f' {prefix}'
prefix = f' {prefix}' if prefix != 'before' else ''
with gr.Accordion(open=False, label="Resize", elem_classes=["small-accordion"], elem_id=f"{tab}_resize_group") if accordion else gr.Group():
with gr.Row():
available_upscalers = [x.name for x in shared.sd_upscalers]
@@ -357,8 +357,8 @@ def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=Tru
with gr.Row(elem_id=f"{tab}_resize_row_fixed"):
with gr.Column(elem_id=f"{tab}_column_fixed1", scale=6):
suffix = '_resize' if tab != 'img2img' else ''
width = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Width {prefix}" if non_zero else "Resize width", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_width")
height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Height {prefix}" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_height")
width = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Width{prefix}" if non_zero else "Resize width", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_width")
height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Height{prefix}" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_height")
with gr.Column(elem_id=f"{tab}_column_fixed2", scale=1):
ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != '']
ar_dropdown = gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_resize_ar", elem_classes=["ar-dropdown"])
@@ -370,7 +370,7 @@ def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=Tru
el = tab.split('_')[0]
detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress=False)
with gr.Tab(label="Scale", id=1, elem_id=f"{tab}_scale_tab_scale") as tab_scale_by:
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label=f"Scale {prefix}" if non_zero else "Resize scale", value=1.0, elem_id=f"{tab}_scale")
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label=f"Scale{prefix}" if non_zero else "Resize scale", value=1.0, elem_id=f"{tab}_scale")
if images is not None:
for component in images:
component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False)