| import gradio as gr
|
| from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES
|
| from core.settings import (
|
| MAX_LORAS, LORA_SOURCE_CHOICES, MAX_EMBEDDINGS, MAX_CONDITIONINGS,
|
| MAX_CONTROLNETS, MAX_IPADAPTERS, RESOLUTION_MAP, ARCHITECTURES_CONFIG,
|
| MODEL_MAP_CHECKPOINT, MODEL_TYPE_MAP, FEATURES_CONFIG, ARCH_CATEGORIES_MAP,
|
| VAE_DIR, MODEL_DEFAULTS_CONFIG
|
| )
|
| import yaml
|
| import os
|
| from functools import lru_cache
|
| from utils.app_utils import save_uploaded_file
|
|
|
| default_model_name = list(MODEL_MAP_CHECKPOINT.keys())[0] if MODEL_MAP_CHECKPOINT else None
|
| default_m_type = MODEL_TYPE_MAP.get(default_model_name, "SDXL") if default_model_name else "SDXL"
|
| default_architectures_dict = ARCHITECTURES_CONFIG.get('architectures', {})
|
| default_arch_model_type = default_architectures_dict.get(default_m_type, {}).get("model_type", default_m_type.lower().replace(" ", "").replace(".", ""))
|
| default_arch_features = FEATURES_CONFIG.get(default_arch_model_type, {})
|
| default_enabled_chains = default_arch_features.get('enabled_chains', [])
|
|
|
| default_vals = MODEL_DEFAULTS_CONFIG.get('Default', {})
|
| DEFAULT_STEPS = default_vals.get('steps', 20)
|
| DEFAULT_CFG = default_vals.get('cfg', 5.0)
|
| DEFAULT_SAMPLER = default_vals.get('sampler_name', 'euler')
|
| DEFAULT_SCHEDULER = default_vals.get('scheduler', 'simple')
|
| DEFAULT_POS_PROMPT = default_vals.get('positive_prompt', '')
|
| DEFAULT_NEG_PROMPT = default_vals.get('negative_prompt', '')
|
|
|
| @lru_cache(maxsize=1)
|
| def get_ipadapter_config_from_yaml():
|
| try:
|
| _PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| _IPADAPTER_LIST_PATH = os.path.join(_PROJECT_ROOT, 'yaml', 'ipadapter.yaml')
|
| with open(_IPADAPTER_LIST_PATH, 'r', encoding='utf-8') as f:
|
| config = yaml.safe_load(f)
|
| return config
|
| except Exception as e:
|
| print(f"Warning: Could not load ipadapter.yaml for UI components: {e}")
|
| return {}
|
|
|
| def get_ipadapter_presets(arch="SDXL"):
|
| config = get_ipadapter_config_from_yaml()
|
| presets = []
|
| if config:
|
| std_presets = config.get("IPAdapter_presets", {}).get(arch, [])
|
| face_presets = config.get("IPAdapter_FaceID_presets", {}).get(arch, [])
|
| if std_presets:
|
| presets.extend(std_presets)
|
| if face_presets:
|
| presets.extend(face_presets)
|
| return presets if presets else ["STANDARD (medium strength)"]
|
|
|
| def create_model_architecture_filter_ui(prefix):
|
| components = {}
|
| ordered_architectures = ARCHITECTURES_CONFIG.get("architecture_order", [])
|
| choices = ["ALL"] + ordered_architectures
|
|
|
| components[f'model_arch_{prefix}'] = gr.Radio(
|
| label="Model Architecture",
|
| choices=choices,
|
| value="ALL",
|
| interactive=True,
|
| visible=True
|
| )
|
| return components
|
|
|
| def create_category_filter_ui(prefix):
|
| valid_cats = list(set(cat for cats in ARCH_CATEGORIES_MAP.values() for cat in cats))
|
| cat_choices = ["ALL"] + sorted(valid_cats)
|
|
|
| components = {}
|
| components[f'model_cat_{prefix}'] = gr.Dropdown(
|
| label="Filter Models",
|
| choices=cat_choices,
|
| value="ALL",
|
| interactive=True,
|
| scale=1,
|
| allow_custom_value=True
|
| )
|
| return components
|
|
|
| def create_base_parameter_ui(prefix, defaults=None):
|
| if defaults is None:
|
| defaults = {}
|
|
|
| components = {}
|
|
|
| with gr.Row():
|
| components[f'aspect_ratio_{prefix}'] = gr.Dropdown(
|
| label="Aspect Ratio",
|
| choices=list(RESOLUTION_MAP.get('sdxl', {}).keys()),
|
| value="1:1 (Square)",
|
| interactive=True,
|
| allow_custom_value=True
|
| )
|
| with gr.Row():
|
| components[f'width_{prefix}'] = gr.Number(label="Width", value=defaults.get('w', 1024), interactive=True)
|
| components[f'height_{prefix}'] = gr.Number(label="Height", value=defaults.get('h', 1024), interactive=True)
|
| with gr.Row():
|
| components[f'sampler_{prefix}'] = gr.Dropdown(
|
| label="Sampler",
|
| choices=SAMPLER_CHOICES,
|
| value=DEFAULT_SAMPLER if DEFAULT_SAMPLER in SAMPLER_CHOICES else (SAMPLER_CHOICES[0] if SAMPLER_CHOICES else 'euler')
|
| )
|
| components[f'scheduler_{prefix}'] = gr.Dropdown(
|
| label="Scheduler",
|
| choices=SCHEDULER_CHOICES,
|
| value=DEFAULT_SCHEDULER if DEFAULT_SCHEDULER in SCHEDULER_CHOICES else (SCHEDULER_CHOICES[0] if SCHEDULER_CHOICES else 'simple')
|
| )
|
| with gr.Row():
|
| components[f'steps_{prefix}'] = gr.Slider(label="Steps", minimum=1, maximum=100, step=1, value=DEFAULT_STEPS)
|
| components[f'cfg_{prefix}'] = gr.Slider(label="CFG Scale", minimum=1.0, maximum=20.0, step=0.1, value=DEFAULT_CFG)
|
| with gr.Row():
|
| components[f'seed_{prefix}'] = gr.Number(label="Seed (-1 for random)", value=-1, precision=0)
|
| components[f'batch_size_{prefix}'] = gr.Slider(label="Batch Size", minimum=1, maximum=16, step=1, value=1)
|
| with gr.Row():
|
| components[f'zero_gpu_{prefix}'] = gr.Number(label="ZeroGPU Duration (s)", value=60, placeholder="Default: 60s", info="Optional: Set how long to reserve the GPU.")
|
|
|
| return components
|
|
|
|
|
| def create_lora_settings_ui(prefix: str):
|
| components = {}
|
|
|
| lora_rows, lora_sources, lora_ids, lora_scales, lora_uploads = [], [], [], [], []
|
|
|
| with gr.Accordion("LoRA Settings", open=False, visible=('lora' in default_enabled_chains)) as lora_accordion:
|
| components[f'lora_accordion_{prefix}'] = lora_accordion
|
| gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. When downloading from Hugging Face, please use the format: `repo_id/filename.extension` or `repo_id/folder_path/filename.extension` (e.g., `lightx2v/Qwen-Image-Lightning/Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors`).")
|
| components[f'lora_count_state_{prefix}'] = gr.State(1)
|
|
|
| for i in range(MAX_LORAS):
|
| with gr.Row(visible=i==0) as row:
|
| source = gr.Dropdown(label=f"LoRA Source {i+1}", choices=LORA_SOURCE_CHOICES, value=LORA_SOURCE_CHOICES[0], scale=1)
|
| lora_id = gr.Textbox(label="Civitai Version ID / HF file / Upload File", scale=2, type="text")
|
| scale = gr.Slider(label=f"Scale", minimum=0.0, maximum=2.0, step=0.05, value=1.0, scale=1)
|
| upload = gr.UploadButton(label="Upload", file_types=[".safetensors"], scale=1)
|
|
|
| lora_rows.append(row)
|
| lora_sources.append(source)
|
| lora_ids.append(lora_id)
|
| lora_scales.append(scale)
|
| lora_uploads.append(upload)
|
|
|
| with gr.Row():
|
| components[f'add_lora_button_{prefix}'] = gr.Button("Add LoRA", variant="secondary")
|
| components[f'delete_lora_button_{prefix}'] = gr.Button("Remove LoRA", variant="secondary", visible=False)
|
|
|
| components[f'lora_rows_{prefix}'] = lora_rows
|
| components[f'lora_sources_{prefix}'] = lora_sources
|
| components[f'lora_ids_{prefix}'] = lora_ids
|
| components[f'lora_scales_{prefix}'] = lora_scales
|
| components[f'lora_uploads_{prefix}'] = lora_uploads
|
|
|
| all_lora_components_flat = []
|
| for i in range(MAX_LORAS):
|
| all_lora_components_flat.extend([lora_sources[i], lora_ids[i], lora_scales[i], lora_uploads[i]])
|
| components[f'all_lora_components_flat_{prefix}'] = all_lora_components_flat
|
|
|
| return components
|
|
|
| def create_controlnet_ui(prefix: str, max_units=MAX_CONTROLNETS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("ControlNet Settings", open=False, visible=('controlnet' in default_enabled_chains)) as accordion:
|
| components[key('controlnet_accordion')] = accordion
|
|
|
| cn_rows, images, series, types, strengths, filepaths = [], [], [], [], [], []
|
| components.update({
|
| key('controlnet_rows'): cn_rows,
|
| key('controlnet_images'): images,
|
| key('controlnet_series'): series,
|
| key('controlnet_types'): types,
|
| key('controlnet_strengths'): strengths,
|
| key('controlnet_filepaths'): filepaths
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"Control Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| types.append(gr.Dropdown(label="Type", choices=[], interactive=True, allow_custom_value=True))
|
| series.append(gr.Dropdown(label="Series", choices=[], interactive=True, allow_custom_value=True))
|
| strengths.append(gr.Slider(label="Strength", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| filepaths.append(gr.State(None))
|
| cn_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_controlnet_button')] = gr.Button("✚ Add ControlNet")
|
| components[key('delete_controlnet_button')] = gr.Button("âž– Delete ControlNet", visible=False)
|
| components[key('controlnet_count_state')] = gr.State(1)
|
|
|
| all_cn_components_flat = []
|
| for i in range(max_units):
|
| all_cn_components_flat.extend([
|
| images[i], types[i], series[i], strengths[i], filepaths[i]
|
| ])
|
| components[key('all_controlnet_components_flat')] = all_cn_components_flat
|
|
|
| return components
|
|
|
| def create_krea2_controlnet_ui(prefix: str, max_units=MAX_CONTROLNETS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Krea2 ControlNet Settings", open=False, visible=('krea2_controlnet' in default_enabled_chains)) as accordion:
|
| components[key('krea2_controlnet_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** Processed using the [facok/comfyui-krea2-controlnet](https://github.com/facok/comfyui-krea2-controlnet) node.")
|
|
|
| cn_rows, images, series, types, strengths, filepaths = [], [], [], [], [], []
|
| components.update({
|
| key('krea2_controlnet_rows'): cn_rows,
|
| key('krea2_controlnet_images'): images,
|
| key('krea2_controlnet_series'): series,
|
| key('krea2_controlnet_types'): types,
|
| key('krea2_controlnet_strengths'): strengths,
|
| key('krea2_controlnet_filepaths'): filepaths
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"Control Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| types.append(gr.Dropdown(label="Type", choices=[], interactive=True, allow_custom_value=True))
|
| series.append(gr.Dropdown(label="Series", choices=[], interactive=True, allow_custom_value=True))
|
| strengths.append(gr.Slider(label="Strength", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| filepaths.append(gr.State(None))
|
| cn_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_krea2_controlnet_button')] = gr.Button("✚ Add Krea2 ControlNet")
|
| components[key('delete_krea2_controlnet_button')] = gr.Button("âž– Delete Krea2 ControlNet", visible=False)
|
| components[key('krea2_controlnet_count_state')] = gr.State(1)
|
|
|
| all_cn_components_flat = []
|
| for i in range(max_units):
|
| all_cn_components_flat.extend([
|
| images[i], types[i], series[i], strengths[i], filepaths[i]
|
| ])
|
| components[key('all_krea2_controlnet_components_flat')] = all_cn_components_flat
|
|
|
| return components
|
|
|
| def create_anima_controlnet_lllite_ui(prefix: str, max_units=MAX_CONTROLNETS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Anima ControlNet LLLite Settings", open=False, visible=('anima_controlnet_lllite' in default_enabled_chains)) as accordion:
|
| components[key('anima_controlnet_lllite_accordion')] = accordion
|
|
|
| cn_rows, images, series, types, strengths, filepaths, start_percents, end_percents = [], [], [], [], [], [], [], []
|
| components.update({
|
| key('anima_controlnet_lllite_rows'): cn_rows,
|
| key('anima_controlnet_lllite_images'): images,
|
| key('anima_controlnet_lllite_series'): series,
|
| key('anima_controlnet_lllite_types'): types,
|
| key('anima_controlnet_lllite_strengths'): strengths,
|
| key('anima_controlnet_lllite_filepaths'): filepaths,
|
| key('anima_controlnet_lllite_start_percents'): start_percents,
|
| key('anima_controlnet_lllite_end_percents'): end_percents
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"Control Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| types.append(gr.Dropdown(label="Type", choices=[], interactive=True, allow_custom_value=True))
|
| series.append(gr.Dropdown(label="Series", choices=[], interactive=True, allow_custom_value=True))
|
| strengths.append(gr.Slider(label="Strength", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| with gr.Row(visible=False):
|
| start_percents.append(gr.State(0.0))
|
| end_percents.append(gr.State(1.0))
|
| filepaths.append(gr.State(None))
|
| cn_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_anima_controlnet_lllite_button')] = gr.Button("✚ Add Lllite")
|
| components[key('delete_anima_controlnet_lllite_button')] = gr.Button("âž– Delete Lllite", visible=False)
|
| components[key('anima_controlnet_lllite_count_state')] = gr.State(1)
|
|
|
| all_cn_components_flat = []
|
| for i in range(max_units):
|
| all_cn_components_flat.extend([
|
| images[i], types[i], series[i], strengths[i], filepaths[i], start_percents[i], end_percents[i]
|
| ])
|
| components[key('all_anima_controlnet_lllite_components_flat')] = all_cn_components_flat
|
|
|
| return components
|
|
|
| def create_diffsynth_controlnet_ui(prefix: str, max_units=MAX_CONTROLNETS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("DiffSynth ControlNet Settings", open=False, visible=('diffsynth_controlnet' in default_enabled_chains)) as accordion:
|
| components[key('diffsynth_controlnet_accordion')] = accordion
|
|
|
| cn_rows, images, series, types, strengths, filepaths = [], [], [], [], [], []
|
| components.update({
|
| key('diffsynth_controlnet_rows'): cn_rows,
|
| key('diffsynth_controlnet_images'): images,
|
| key('diffsynth_controlnet_series'): series,
|
| key('diffsynth_controlnet_types'): types,
|
| key('diffsynth_controlnet_strengths'): strengths,
|
| key('diffsynth_controlnet_filepaths'): filepaths
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"Control Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| types.append(gr.Dropdown(label="Type", choices=[], interactive=True, allow_custom_value=True))
|
| series.append(gr.Dropdown(label="Series", choices=[], interactive=True, allow_custom_value=True))
|
| strengths.append(gr.Slider(label="Strength", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| filepaths.append(gr.State(None))
|
| cn_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_diffsynth_controlnet_button')] = gr.Button("✚ Add DiffSynth ControlNet")
|
| components[key('delete_diffsynth_controlnet_button')] = gr.Button("âž– Delete DiffSynth ControlNet", visible=False)
|
| components[key('diffsynth_controlnet_count_state')] = gr.State(1)
|
|
|
| all_cn_components_flat = []
|
| for i in range(max_units):
|
| all_cn_components_flat.extend([
|
| images[i], types[i], series[i], strengths[i], filepaths[i]
|
| ])
|
| components[key('all_diffsynth_controlnet_components_flat')] = all_cn_components_flat
|
|
|
| return components
|
|
|
| def create_ipadapter_ui(prefix: str, max_units=MAX_IPADAPTERS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| sdxl_presets = get_ipadapter_presets("SDXL")
|
| default_preset = sdxl_presets[0] if sdxl_presets else None
|
|
|
| with gr.Accordion("IPAdapter Settings", open=False, visible=('ipadapter' in default_enabled_chains)) as accordion:
|
| components[key('ipadapter_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** Processed using the [cubiq/ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) node.")
|
|
|
| with gr.Row():
|
| components[key('ipadapter_final_preset')] = gr.Dropdown(
|
| label="Preset (for all images)",
|
| choices=sdxl_presets,
|
| value=default_preset,
|
| interactive=True,
|
| allow_custom_value=True
|
| )
|
| components[key('ipadapter_embeds_scaling')] = gr.Dropdown(
|
| label="Embeds Scaling",
|
| choices=['V only', 'K+V', 'K+V w/ C penalty', 'K+mean(V) w/ C penalty'],
|
| value='V only',
|
| interactive=True
|
| )
|
|
|
| with gr.Row():
|
| components[key('ipadapter_combine_method')] = gr.Dropdown(
|
| label="Combine Method",
|
| choices=["concat", "add", "subtract", "average", "norm average", "max", "min"],
|
| value="concat",
|
| interactive=True
|
| )
|
| components[key('ipadapter_final_weight')] = gr.Slider(label="Final Weight", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True)
|
| components[key('ipadapter_final_lora_strength')] = gr.Slider(label="Final LoRA Strength", minimum=0.0, maximum=2.0, step=0.05, value=0.6, interactive=True, visible=False)
|
|
|
| gr.Markdown("---")
|
|
|
| ipa_rows, images, weights, lora_strengths = [], [], [], []
|
| components.update({
|
| key('ipadapter_rows'): ipa_rows,
|
| key('ipadapter_images'): images,
|
| key('ipadapter_weights'): weights,
|
| key('ipadapter_lora_strengths'): lora_strengths
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"IPAdapter Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| weights.append(gr.Slider(label="Weight", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| lora_strengths.append(gr.Slider(label="LoRA Strength", minimum=0.0, maximum=2.0, step=0.05, value=0.6, interactive=True, visible=False))
|
| ipa_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_ipadapter_button')] = gr.Button("✚ Add IPAdapter")
|
| components[key('delete_ipadapter_button')] = gr.Button("âž– Delete IPAdapter", visible=False)
|
| components[key('ipadapter_count_state')] = gr.State(1)
|
|
|
| all_ipa_components_flat = images + weights + lora_strengths
|
| all_ipa_components_flat += [
|
| components[key('ipadapter_final_preset')],
|
| components[key('ipadapter_final_weight')],
|
| components[key('ipadapter_final_lora_strength')],
|
| components[key('ipadapter_embeds_scaling')],
|
| components[key('ipadapter_combine_method')],
|
| ]
|
| components[key('all_ipadapter_components_flat')] = all_ipa_components_flat
|
|
|
| return components
|
|
|
| def create_flux1_ipadapter_ui(prefix: str, max_units=MAX_IPADAPTERS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("IPAdapter Settings (FLUX.1)", open=False, visible=('flux1_ipadapter' in default_enabled_chains)) as accordion:
|
| components[key('flux1_ipadapter_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** Processed using the [Shakker-Labs/ComfyUI-IPAdapter-Flux](https://github.com/Shakker-Labs/ComfyUI-IPAdapter-Flux) node.")
|
|
|
| ipa_rows, images, weights, start_percents, end_percents = [], [], [], [], []
|
| components.update({
|
| key('flux1_ipadapter_rows'): ipa_rows,
|
| key('flux1_ipadapter_images'): images,
|
| key('flux1_ipadapter_weights'): weights,
|
| key('flux1_ipadapter_start_percents'): start_percents,
|
| key('flux1_ipadapter_end_percents'): end_percents,
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"IPAdapter Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| weights.append(gr.Slider(label="Weight", minimum=0.0, maximum=2.0, step=0.05, value=0.6, interactive=True))
|
| with gr.Row():
|
| start_percents.append(gr.Slider(label="Start At", minimum=0.0, maximum=1.0, step=0.01, value=0.0, interactive=True))
|
| end_percents.append(gr.Slider(label="End At", minimum=0.0, maximum=1.0, step=0.01, value=0.6, interactive=True))
|
| ipa_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_flux1_ipadapter_button')] = gr.Button("✚ Add IPAdapter (FLUX)")
|
| components[key('delete_flux1_ipadapter_button')] = gr.Button("âž– Delete IPAdapter (FLUX)", visible=False)
|
| components[key('flux1_ipadapter_count_state')] = gr.State(1)
|
|
|
| all_flux1_ipa_components_flat = images + weights + start_percents + end_percents
|
| components[key('all_flux1_ipadapter_components_flat')] = all_flux1_ipa_components_flat
|
|
|
| return components
|
|
|
| def create_sd3_ipadapter_ui(prefix: str, max_units=MAX_IPADAPTERS):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("IPAdapter Settings (SD3)", open=False, visible=('sd3_ipadapter' in default_enabled_chains)) as accordion:
|
| components[key('sd3_ipadapter_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** Processed using the [Slickytail/ComfyUI-InstantX-IPAdapter-SD3](https://github.com/Slickytail/ComfyUI-InstantX-IPAdapter-SD3) node.")
|
|
|
| ipa_rows, images, weights, start_percents, end_percents = [], [], [], [], []
|
| components.update({
|
| key('sd3_ipadapter_rows'): ipa_rows,
|
| key('sd3_ipadapter_images'): images,
|
| key('sd3_ipadapter_weights'): weights,
|
| key('sd3_ipadapter_start_percents'): start_percents,
|
| key('sd3_ipadapter_end_percents'): end_percents,
|
| })
|
|
|
| for i in range(max_units):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"IPAdapter Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| weights.append(gr.Slider(label="Weight", minimum=0.0, maximum=2.0, step=0.05, value=0.5, interactive=True))
|
| with gr.Row():
|
| start_percents.append(gr.Slider(label="Start At", minimum=0.0, maximum=1.0, step=0.01, value=0.0, interactive=True))
|
| end_percents.append(gr.Slider(label="End At", minimum=0.0, maximum=1.0, step=0.01, value=1.0, interactive=True))
|
| ipa_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_sd3_ipadapter_button')] = gr.Button("✚ Add IPAdapter (SD3)")
|
| components[key('delete_sd3_ipadapter_button')] = gr.Button("âž– Delete IPAdapter (SD3)", visible=False)
|
| components[key('sd3_ipadapter_count_state')] = gr.State(1)
|
|
|
| all_sd3_ipa_components_flat = images + weights + start_percents + end_percents
|
| components[key('all_sd3_ipadapter_components_flat')] = all_sd3_ipa_components_flat
|
|
|
| return components
|
|
|
| def create_style_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Style Settings (FLUX.1)", open=False, visible=('style' in default_enabled_chains)) as accordion:
|
| components[key('style_accordion')] = accordion
|
|
|
| style_rows, images, strengths = [], [], []
|
| components.update({
|
| key('style_rows'): style_rows,
|
| key('style_images'): images,
|
| key('style_strengths'): strengths
|
| })
|
|
|
| for i in range(5):
|
| with gr.Row(visible=(i < 1)) as row:
|
| with gr.Column(scale=1):
|
| images.append(gr.Image(label=f"Style Image {i+1}", type="pil", sources=["upload"], height=256))
|
| with gr.Column(scale=2):
|
| strengths.append(gr.Slider(label="Strength", minimum=0.0, maximum=2.0, step=0.05, value=1.0, interactive=True))
|
| style_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_style_button')] = gr.Button("✚ Add Style (FLUX)")
|
| components[key('delete_style_button')] = gr.Button("âž– Delete Style (FLUX)", visible=False)
|
| components[key('style_count_state')] = gr.State(1)
|
|
|
| all_style_components_flat = images + strengths
|
| components[key('all_style_components_flat')] = all_style_components_flat
|
|
|
| return components
|
|
|
| def create_embedding_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Embedding Settings", open=False, visible=('embedding' in default_enabled_chains)) as accordion:
|
| components[key('embedding_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. For example, entering the Version ID 456 will automatically save the file as \"civitai/456.safetensors\", and you will need to manually enter `embedding:civitai/456` in either your prompt or negative prompt to activate it. When downloading from Hugging Face, please use the format: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., ilikebigturtles/lazypos/lazypos.safetensors or ilikebigturtles/lazyneg/lazyneg.safetensors). For Hugging Face files, you will need to enter embedding:huggingface/filename (e.g., entering embedding:huggingface/lazypos in your positive prompt, or embedding:huggingface/lazyneg in your negative prompt) to activate it. For uploaded files, enter `embedding:upload_file/filename` in either your positive prompt or negative prompt to activate it.")
|
|
|
| embedding_rows, sources, ids, files, upload_buttons = [], [], [], [], []
|
| components.update({
|
| key('embedding_rows'): embedding_rows,
|
| key('embeddings_sources'): sources,
|
| key('embeddings_ids'): ids,
|
| key('embeddings_files'): files,
|
| key('embeddings_uploads'): upload_buttons
|
| })
|
|
|
| for i in range(MAX_EMBEDDINGS):
|
| with gr.Row(visible=(i < 1)) as row:
|
| sources.append(gr.Dropdown(label=f"Embedding Source {i+1}", choices=LORA_SOURCE_CHOICES, value="Civitai", scale=1, interactive=True))
|
| ids.append(gr.Textbox(label="Civitai Version ID / HF file / Upload File", scale=3, interactive=True, type="text"))
|
| upload_btn = gr.UploadButton("Upload", file_types=[".safetensors"], scale=1)
|
| files.append(gr.State(None))
|
| upload_buttons.append(upload_btn)
|
| embedding_rows.append(row)
|
|
|
| with gr.Row():
|
| components[key('add_embedding_button')] = gr.Button("✚ Add Embedding")
|
| components[key('delete_embedding_button')] = gr.Button("âž– Delete Embedding", visible=False)
|
| components[key('embedding_count_state')] = gr.State(1)
|
|
|
| all_embedding_components_flat = []
|
| for i in range(MAX_EMBEDDINGS):
|
| all_embedding_components_flat.extend([sources[i], ids[i], files[i]])
|
| components[key('all_embedding_components_flat')] = all_embedding_components_flat
|
|
|
| return components
|
|
|
| def create_conditioning_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Conditioning Settings", open=False, visible=('conditioning' in default_enabled_chains)) as accordion:
|
| components[key('conditioning_accordion')] = accordion
|
| gr.Markdown("💡 **Tip:** Define rectangular areas and assign specific prompts to them. Coordinates (X, Y) start from the top-left corner.")
|
|
|
| cond_rows, prompts, widths, heights, xs, ys, strengths = [], [], [], [], [], [], []
|
| components.update({
|
| key('conditioning_rows'): cond_rows,
|
| key('conditioning_prompts'): prompts,
|
| key('conditioning_widths'): widths,
|
| key('conditioning_heights'): heights,
|
| key('conditioning_xs'): xs,
|
| key('conditioning_ys'): ys,
|
| key('conditioning_strengths'): strengths
|
| })
|
|
|
| for i in range(MAX_CONDITIONINGS):
|
| with gr.Column(visible=(i < 1)) as row_wrapper:
|
| prompts.append(gr.Textbox(label=f"Area Prompt {i+1}", lines=2, interactive=True))
|
| with gr.Row():
|
| xs.append(gr.Number(label="X", value=0, interactive=True, step=8, scale=1))
|
| ys.append(gr.Number(label="Y", value=0, interactive=True, step=8, scale=1))
|
| widths.append(gr.Number(label="Width", value=512, interactive=True, step=8, scale=1))
|
| heights.append(gr.Number(label="Height", value=512, interactive=True, step=8, scale=1))
|
| strengths.append(gr.Slider(label="Strength", minimum=0.1, maximum=2.0, step=0.05, value=1.0, interactive=True, scale=2))
|
| cond_rows.append(row_wrapper)
|
|
|
| with gr.Row():
|
| components[key('add_conditioning_button')] = gr.Button("✚ Add Area")
|
| components[key('delete_conditioning_button')] = gr.Button("âž– Delete Area", visible=False)
|
| components[key('conditioning_count_state')] = gr.State(1)
|
|
|
| all_cond_components_flat = prompts + widths + heights + xs + ys + strengths
|
| components[key('all_conditioning_components_flat')] = all_cond_components_flat
|
|
|
| return components
|
|
|
| def on_vae_upload(file_obj):
|
| if not file_obj:
|
| return gr.update(), gr.update(), None
|
|
|
| uploaded_filename = save_uploaded_file(file_obj, VAE_DIR)
|
| return uploaded_filename, "Upload File", file_obj
|
|
|
| def create_vae_override_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("VAE Settings (Override)", open=False, visible=('vae' in default_enabled_chains)) as vae_accordion:
|
| components[key('vae_accordion')] = vae_accordion
|
| gr.Markdown("💡 **Tip:** When downloading from Civitai, please use the **Version ID**, not the Model ID. You can find the Version ID in the URL (e.g., `civitai.com/models/123?modelVersionId=456`) or under the model's download button. When downloading from Hugging Face, please use the format: `repo_id/filename.extension` or `repo_id/folder_path/filename.extension` (e.g., `madebyollin/sdxl-vae-fp16-fix/sdxl_vae.safetensors`).")
|
| with gr.Row():
|
| components[key('vae_source')] = gr.Dropdown(
|
| label="VAE Source",
|
| choices=LORA_SOURCE_CHOICES,
|
| value="Civitai",
|
| scale=1,
|
| interactive=True
|
| )
|
| components[key('vae_id')] = gr.Textbox(
|
| label="Civitai Version ID / HF file / Upload File",
|
| scale=3,
|
| interactive=True,
|
| type="text"
|
| )
|
| upload_btn = gr.UploadButton(
|
| "Upload",
|
| file_types=[".safetensors"],
|
| scale=1
|
| )
|
| components[key('vae_upload_button')] = upload_btn
|
| components[key('vae_file')] = gr.State(None)
|
|
|
| upload_btn.upload(
|
| fn=on_vae_upload,
|
| inputs=[upload_btn],
|
| outputs=[components[key('vae_id')], components[key('vae_source')], components[key('vae_file')]]
|
| )
|
|
|
| return components
|
|
|
| def create_reference_latent_ui(prefix: str, max_units=10):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Reference Edit Settings", open=False, visible=('reference_latent' in default_enabled_chains)) as ref_accordion:
|
| components[key('reference_latent_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('reference_latent_rows')] = ref_image_groups
|
| components[key('reference_latent_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_reference_latent_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_reference_latent_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('reference_latent_count_state')] = gr.State(1)
|
|
|
| components[key('all_reference_latent_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_hidream_o1_reference_ui(prefix: str, max_units=10):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("HiDream-O1 Reference Edit Settings", open=False, visible=('hidream_o1_reference' in default_enabled_chains)) as ref_accordion:
|
| components[key('hidream_o1_reference_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** Please use **HiDream-O1-Image-Dev** (HiDream-O1-Image will time out), and set the resolution to **4.0MP** (e.g., 2048x2048). In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('hidream_o1_reference_rows')] = ref_image_groups
|
| components[key('hidream_o1_reference_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_hidream_o1_reference_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_hidream_o1_reference_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('hidream_o1_reference_count_state')] = gr.State(1)
|
|
|
| components[key('all_hidream_o1_reference_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_sensenova_reference_ui(prefix: str, max_units=10):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("SenseNova Reference Edit Settings", open=False, visible=('sensenova_reference' in default_enabled_chains)) as ref_accordion:
|
| components[key('sensenova_reference_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** For SenseNova models, this feature enables reference image editing and combining capabilities. In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('sensenova_reference_rows')] = ref_image_groups
|
| components[key('sensenova_reference_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_sensenova_reference_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_sensenova_reference_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('sensenova_reference_count_state')] = gr.State(1)
|
|
|
| components[key('all_sensenova_reference_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_joyai_reference_ui(prefix: str, max_units=2):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("JoyAI Reference Edit Settings", open=False, visible=('joyai_image' in default_enabled_chains)) as ref_accordion:
|
| components[key('joyai_reference_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an **Image Edit** (JoyAI-Image-Edit recommended), while adding multiple images performs an **Image Combine** (JoyAI-Image-Edit-Plus recommended with ZeroGPU Duration (s) set to 120).")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('joyai_reference_rows')] = ref_image_groups
|
| components[key('joyai_reference_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_joyai_reference_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_joyai_reference_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('joyai_reference_count_state')] = gr.State(1)
|
|
|
| components[key('all_joyai_reference_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_reference_image_ui(prefix: str, max_units=10):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Reference Image Edit Settings", open=False, visible=('reference_image' in default_enabled_chains)) as ref_accordion:
|
| components[key('reference_image_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('reference_image_rows')] = ref_image_groups
|
| components[key('reference_image_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_reference_image_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_reference_image_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('reference_image_count_state')] = gr.State(1)
|
|
|
| components[key('all_reference_image_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_pid_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("PiD Settings", open=False, visible=('pid' in default_enabled_chains)) as pid_accordion:
|
| components[key('pid_accordion')] = pid_accordion
|
| gr.Markdown("💡 **Tip:** Use PiD (Pixel Diffusion Decoder) instead of the VAE Decoder for 4x decoding.")
|
| with gr.Row():
|
| components[key('pid_settings')] = gr.Dropdown(
|
| label="PiD Mode",
|
| choices=["OFF", "ON"],
|
| value="OFF",
|
| interactive=True
|
| )
|
|
|
| return components
|
|
|
| def create_krea2_identity_edit_ui(prefix: str, max_units=2):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Krea2 Identity Edit Settings", open=False, visible=('krea2_identity_edit' in default_enabled_chains)) as ref_accordion:
|
| components[key('krea2_identity_edit_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** Processed using the [lbouaraba/comfyui-krea2edit](https://github.com/lbouaraba/comfyui-krea2edit) node. (Krea-2-Turbo recommended, Krea-2-Raw need set ZeroGPU Duration (s) to 120 ) In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('krea2_identity_edit_rows')] = ref_image_groups
|
| components[key('krea2_identity_edit_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_krea2_identity_edit_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_krea2_identity_edit_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('krea2_identity_edit_count_state')] = gr.State(1)
|
|
|
| components[key('all_krea2_identity_edit_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_qwen_image_edit_ui(prefix: str, max_units=3):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Qwen-Image Edit Settings", open=False, visible=('qwen_image_edit' in default_enabled_chains)) as ref_accordion:
|
| components[key('qwen_image_edit_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** (lightx2v/Qwen-Image-Edit-2511-Lightning recommended) In txt2img mode, adding a single reference image performs an **Image Edit**, while adding multiple images performs an **Image Combine**.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('qwen_image_edit_rows')] = ref_image_groups
|
| components[key('qwen_image_edit_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_qwen_image_edit_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_qwen_image_edit_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('qwen_image_edit_count_state')] = gr.State(1)
|
|
|
| components[key('all_qwen_image_edit_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
| def create_krea2_reference_edit_ui(prefix: str, max_units=3):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Krea2 Style Reference Edit Settings", open=False, visible=('krea2_style_reference' in default_enabled_chains)) as ref_accordion:
|
| components[key('krea2_reference_edit_accordion')] = ref_accordion
|
| gr.Markdown("💡 **Tip:** (Krea-2-Turbo recommended) Add style reference images to perform style reference editing.")
|
|
|
| ref_image_groups = []
|
| ref_image_inputs = []
|
| with gr.Row():
|
| for i in range(max_units):
|
| with gr.Column(visible=(i < 1), min_width=160) as img_col:
|
| img_comp = gr.Image(type="pil", label=f"Ref. {i+1}", sources=["upload"], height=150)
|
| ref_image_groups.append(img_col)
|
| ref_image_inputs.append(img_comp)
|
|
|
| components[key('krea2_reference_edit_rows')] = ref_image_groups
|
| components[key('krea2_reference_edit_images')] = ref_image_inputs
|
|
|
| with gr.Row():
|
| components[key('add_krea2_reference_edit_button')] = gr.Button("✚ Add Reference Image")
|
| components[key('delete_krea2_reference_edit_button')] = gr.Button("âž– Delete Reference Image", visible=False)
|
| components[key('krea2_reference_edit_count_state')] = gr.State(1)
|
|
|
| components[key('all_krea2_reference_edit_components_flat')] = ref_image_inputs
|
|
|
| return components
|
|
|
|
|
| def create_qwen_image_2_1_prompt_enhancer_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Qwen-Image-2.1 Prompt Enhancer Settings", open=False, visible=('qwen_image_2_1_prompt_enhancer' in default_enabled_chains)) as enhancer_accordion:
|
| components[key('qwen_image_2_1_prompt_enhancer_accordion')] = enhancer_accordion
|
| gr.Markdown("💡 **Tip:** Automatically selects between [Qwen-Image-2.1-PE-T2I](https://huggingface.co/Qwen/Qwen-Image-2.1-PE-T2I) and [Qwen-Image-2.1-PE-I2I](https://huggingface.co/Qwen/Qwen-Image-2.1-PE-I2I) for prompt enhancement based on input context.")
|
| with gr.Row():
|
| components[key('qwen_image_2_1_prompt_enhancer_enable')] = gr.Checkbox(
|
| label="Enable Qwen-Image-2.1 Prompt Enhancer",
|
| value=False,
|
| interactive=True,
|
| scale=2
|
| )
|
| components[key('qwen_image_2_1_prompt_enhancer_thinking')] = gr.Checkbox(
|
| label="Enable Thinking (Requires longer ZeroGPU Duration)",
|
| value=False,
|
| interactive=True,
|
| scale=2
|
| )
|
| components[key('qwen_image_2_1_prompt_enhancer_max_length')] = gr.Number(
|
| label="Max Length",
|
| value=4096,
|
| precision=0,
|
| minimum=16,
|
| step=16,
|
| interactive=True,
|
| scale=1
|
| )
|
|
|
| return components
|
|
|
|
|
| DEFAULT_MING_IMAGE_SYSTEM_PROMPT = (
|
| "You are a senior visual designer and image-prompt engineer. Expand the user's request into one precise, high-resolution Figma-style caption. Return only one JSON object. "
|
| "Use exactly two top-level keys. `canvas_settings` contains exactly `aspect_ratio`, `ambient_lighting`, and `image_style`. `layers` lists visible groups from background to topmost overlay. Every layer contains exactly `description`, `coordinates`, `hierarchy_and_relation`, and `color_specs`; `color_specs` is an array of hex colors. "
|
| '`coordinates` MUST be one string, never an object or array, in exactly this form: `"cx: 0.500, cy: 0.500, w: 1.000, h: 1.000"`. Values are normalized; each bbox encloses its complete owned object and stays inside the canvas. '
|
| "A layer is one selectable visible semantic group: background, full person, coherent object, panel, card, row, or text block. Prefer the fewest groups that preserve the layout. Keep people and objects intact. Never create invisible parents, guides, placeholders, empty layers, duplicate summaries, or multiple owners for one element. "
|
| "Preserve every user-supplied rendered string character-for-character and as one contiguous string. Unless multiple visible copies are requested, it must occur exactly once across all `description` fields and zero times in `hierarchy_and_relation`. Quote it only where describing its visible rendering; refer to the related subject elsewhere with unquoted semantic wording. Enumerate intended copy, invent extra copy sparingly, and never hide content behind \"other text\", \"remaining labels\", or \"etc.\" "
|
| "Describe concrete composition, typography, materials, texture, lighting, pose, and camera treatment without literary filler. Use `hierarchy_and_relation` only for ownership, alignment, containment, stacking, and occlusion. "
|
| "Infer structured layouts first. Use one complete layer per card and state its row and column. A compact secondary table may be one layer only if every header and cell is listed; otherwise use a visible shared frame when present, one complete header, and one complete layer per body row, binding values to columns and stating blanks. Enumerate sequences, schedules, spans, gaps, and vacant tracks in visual order. Do not mistake ordinary alignment for a table. "
|
| "Silently verify schema, string coordinates, Z-order, exact-text counts, geometry, bbox validity, and completeness."
|
| )
|
|
|
|
|
| def create_ming_image_prompt_enhancer_ui(prefix: str):
|
| components = {}
|
| key = lambda name: f"{name}_{prefix}"
|
|
|
| with gr.Accordion("Ming-Image Prompt Enhancer Settings", open=False, visible=('ming_image_prompt_enhancer' in default_enabled_chains)) as enhancer_accordion:
|
| components[key('ming_image_prompt_enhancer_accordion')] = enhancer_accordion
|
| gr.Markdown("💡 **Tip:** Leverages [Qwen3.8-27B](https://huggingface.co/Qwen/Qwen3.8-27B) guided by the official [System Prompt](https://github.com/inclusionAI/Ming-Image#text-to-image-prompt-rewriting) to automatically enhance prompts into structured layouts based on input context.")
|
| with gr.Row():
|
| components[key('ming_image_prompt_enhancer_enable')] = gr.Checkbox(
|
| label="Enable Ming-Image Prompt Enhancer",
|
| value=False,
|
| interactive=True,
|
| scale=2
|
| )
|
| components[key('ming_image_prompt_enhancer_thinking')] = gr.Checkbox(
|
| label="Enable Thinking (Requires longer ZeroGPU Duration)",
|
| value=False,
|
| interactive=True,
|
| scale=2
|
| )
|
| components[key('ming_image_prompt_enhancer_max_length')] = gr.Number(
|
| label="Max Length",
|
| value=4096,
|
| precision=0,
|
| minimum=16,
|
| step=16,
|
| interactive=True,
|
| scale=1
|
| )
|
| components[key('ming_image_prompt_enhancer_system_prompt')] = gr.Textbox(
|
| label="System Prompt",
|
| value=DEFAULT_MING_IMAGE_SYSTEM_PROMPT,
|
| lines=4,
|
| max_lines=12,
|
| interactive=True
|
| )
|
|
|
| return components
|