Spaces:
Running on Zero
Running on Zero
Download ui/shared/studio_ui.py from BlueSkyXN/ImageGen-Studio: direct link, hf CLI and curl.
- Browser
- Download file 17.8 kB
-
https://huggingface.co/spaces/BlueSkyXN/ImageGen-Studio/resolve/main/ui/shared/studio_ui.py
- Command line
-
hf download hf://spaces/BlueSkyXN/ImageGen-Studio/ui/shared/studio_ui.py
-
curl -L -o studio_ui.py https://huggingface.co/spaces/BlueSkyXN/ImageGen-Studio/resolve/main/ui/shared/studio_ui.py
17.8 kB
| """One shared, task-switchable UI instead of five duplicated forms.""" | |
| from __future__ import annotations | |
| import gradio as gr | |
| from comfy_integration.nodes import SAMPLER_CHOICES, SCHEDULER_CHOICES | |
| from core.execution_plan import available_run_modes | |
| from core.runtime_config import CONFIG | |
| from core.settings import ( | |
| ARCHITECTURES_CONFIG, | |
| MODEL_DEFAULTS_CONFIG, | |
| MODEL_MAP_CHECKPOINT, | |
| MODEL_TYPE_MAP, | |
| RESOLUTION_MAP, | |
| ) | |
| from ui.guidance import QUICK_PRESETS, model_hint, prompt_guidance, task_help | |
| from .ui_components import ( | |
| create_anima_controlnet_lllite_ui, | |
| create_boogu_edit_ui, | |
| create_category_filter_ui, | |
| create_conditioning_ui, | |
| create_controlnet_ui, | |
| create_diffsynth_controlnet_ui, | |
| create_embedding_ui, | |
| create_flux1_ipadapter_ui, | |
| create_hidream_o1_reference_ui, | |
| create_ipadapter_ui, | |
| create_joyai_reference_ui, | |
| create_krea2_controlnet_ui, | |
| create_krea2_identity_edit_ui, | |
| create_krea2_reference_edit_ui, | |
| create_lora_settings_ui, | |
| create_model_architecture_filter_ui, | |
| create_pid_ui, | |
| create_qwen_image_edit_ui, | |
| create_reference_image_ui, | |
| create_reference_latent_ui, | |
| create_sd3_ipadapter_ui, | |
| create_style_ui, | |
| create_vae_override_ui, | |
| ) | |
| TASK_CHOICES = [ | |
| ("✨ 文生图", "txt2img"), | |
| ("参考图编辑 / 融合", "reference"), | |
| ("🖼️ 图生图(整体重绘)", "img2img"), | |
| ("🖌️ 局部重绘", "inpaint"), | |
| ("↔️ 扩图", "outpaint"), | |
| ("🔎 高清修复", "hires_fix"), | |
| ] | |
| def create_ui() -> dict: | |
| prefix = "studio" | |
| components: dict = {"_task_prefixes": [(prefix, None)]} | |
| default_values = MODEL_DEFAULTS_CONFIG.get("Default", {}) | |
| default_model = next(iter(MODEL_MAP_CHECKPOINT), None) | |
| prompt_info = prompt_guidance("txt2img", "single", default_model) | |
| default_architecture = MODEL_TYPE_MAP.get(default_model, "SDXL") | |
| default_architecture_info = ARCHITECTURES_CONFIG.get("architectures", {}).get( | |
| default_architecture, {} | |
| ) | |
| default_resolution_key = default_architecture_info.get("model_type", "sdxl") | |
| default_resolution_map = RESOLUTION_MAP.get( | |
| default_resolution_key, RESOLUTION_MAP.get("sdxl", {}) | |
| ) | |
| default_aspect = next(iter(default_resolution_map), "1:1 (Square)") | |
| default_width, default_height = default_resolution_map.get(default_aspect, (1024, 1024)) | |
| components[f"task_type_{prefix}"] = gr.Radio( | |
| choices=TASK_CHOICES, | |
| value="txt2img", | |
| label="1. 选择任务", | |
| elem_id="task-switcher", | |
| ) | |
| components[f"task_help_{prefix}"] = gr.Markdown( | |
| task_help("txt2img"), elem_classes="task-help" | |
| ) | |
| with gr.Row(equal_height=False, elem_id="workspace-row"): | |
| with gr.Column(scale=7, min_width=360): | |
| with gr.Accordion("2. 选择模型", open=True): | |
| components[f"quick_preset_{prefix}"] = gr.Dropdown( | |
| choices=QUICK_PRESETS, | |
| value="__manual__", | |
| label="快速方案", | |
| info="只是帮你定位模型;仍可继续调整所有参数。", | |
| interactive=True, | |
| ) | |
| components.update(create_model_architecture_filter_ui(prefix)) | |
| with gr.Row(): | |
| components.update(create_category_filter_ui(prefix)) | |
| components[f"base_model_{prefix}"] = gr.Dropdown( | |
| label="具体模型", | |
| choices=list(MODEL_MAP_CHECKPOINT.keys()), | |
| value=default_model, | |
| filterable=True, | |
| allow_custom_value=False, | |
| scale=3, | |
| interactive=True, | |
| ) | |
| components[f"model_hint_{prefix}"] = gr.Markdown( | |
| model_hint(default_model) if default_model else "暂无可用模型。", | |
| elem_classes="model-hint", | |
| ) | |
| with gr.Accordion("图片输入与运行方式", open=True): | |
| components[f"run_mode_{prefix}"] = gr.Dropdown( | |
| choices=available_run_modes("txt2img", default_model), | |
| value="single", | |
| label="运行方式", | |
| info="所有模式都顺序执行,不会同时把多个大模型塞进显存。", | |
| ) | |
| components[f"pk_models_{prefix}"] = gr.Dropdown( | |
| choices=list(MODEL_MAP_CHECKPOINT.keys()), | |
| value=[], | |
| multiselect=True, | |
| max_choices=max(1, CONFIG.max_pk_models - 1), | |
| label="额外对比模型", | |
| info=f"当前模型会自动加入;最多合计 {CONFIG.max_pk_models} 个。", | |
| filterable=True, | |
| visible=False, | |
| ) | |
| components[f"batch_images_{prefix}"] = gr.File( | |
| file_count="multiple", | |
| file_types=["image"], | |
| type="filepath", | |
| allow_reordering=True, | |
| label="图片列表(按顺序编号,可拖动排序)", | |
| visible=False, | |
| ) | |
| with gr.Row(): | |
| components[f"reference_role_{prefix}"] = gr.Dropdown( | |
| choices=[ | |
| ("自动匹配模型能力", "auto"), | |
| ("人物 / 身份参考", "identity"), | |
| ("风格参考", "style"), | |
| ], | |
| value="auto", | |
| label="多图融合用途", | |
| visible=False, | |
| ) | |
| components[f"pk_model_defaults_{prefix}"] = gr.Checkbox( | |
| value=True, | |
| label="PK 使用各模型推荐采样参数", | |
| info="Prompt、尺寸与种子保持一致;步数和 CFG 按模型推荐值。", | |
| visible=False, | |
| ) | |
| components[f"input_hint_{prefix}"] = gr.Markdown( | |
| "**怎么选:** 多图独立是 A→A′、B→B′;多图×多模型会执行图片和模型的组合;" | |
| "需要按指令修改或融合素材,请选择上方“参考图编辑 / 融合”。" | |
| ) | |
| components[f"input_preview_{prefix}"] = gr.Gallery( | |
| label="本次有效图片(空槽位不编号)", columns=4, rows=1, height=200, | |
| object_fit="contain", interactive=False, visible=False, | |
| elem_id="input-image-preview", | |
| ) | |
| with gr.Group(elem_classes="prompt-card"): | |
| components[f"prompt_{prefix}"] = gr.Textbox( | |
| label=prompt_info["label"], | |
| placeholder=prompt_info["placeholder"], | |
| lines=4, | |
| max_lines=8, | |
| value=default_values.get("positive_prompt", ""), | |
| ) | |
| components[f"prompt_help_{prefix}"] = gr.Markdown(prompt_info["help"]) | |
| with gr.Accordion("负面提示词(可选)", open=False): | |
| components[f"neg_prompt_{prefix}"] = gr.Textbox( | |
| label="不希望出现的内容", | |
| placeholder="例如:低质量、模糊、多余手指、水印", | |
| lines=2, | |
| value=default_values.get("negative_prompt", ""), | |
| info="是否生效取决于模型和 CFG;CFG=1 的常见采样路径通常不使用负面分支。", | |
| ) | |
| components[f"prompt_examples_{prefix}"] = gr.Dataset( | |
| samples=prompt_info["examples"], | |
| components=["textbox"], type="values", | |
| label="点一下填入示例", | |
| ) | |
| with gr.Group(visible=False) as source_panel: | |
| components[f"source_image_{prefix}"] = gr.Image( | |
| type="pil", | |
| label="源图片", | |
| sources=["upload", "clipboard"], | |
| height=300, | |
| ) | |
| components[f"source_panel_{prefix}"] = source_panel | |
| with gr.Group(visible=False) as inpaint_panel: | |
| gr.Markdown("涂抹需要替换的区域;未涂抹部分会尽量保留。") | |
| components[f"inpaint_image_dict_{prefix}"] = gr.ImageEditor( | |
| type="pil", | |
| label="图片与蒙版", | |
| sources=["upload", "clipboard"], | |
| height=420, | |
| ) | |
| with gr.Row(): | |
| components[f"inpaint_denoise_{prefix}"] = gr.Slider( | |
| 0.0, 1.0, value=1.0, step=0.05, label="局部重绘幅度" | |
| ) | |
| components[f"grow_mask_by_{prefix}"] = gr.Slider( | |
| 0, 64, value=6, step=1, label="蒙版外扩像素" | |
| ) | |
| components[f"inpaint_panel_{prefix}"] = inpaint_panel | |
| with gr.Group(visible=False) as img2img_panel: | |
| components[f"img2img_denoise_{prefix}"] = gr.Slider( | |
| 0.0, | |
| 1.0, | |
| value=0.7, | |
| step=0.01, | |
| label="重绘幅度", | |
| info="0 更接近原图,1 改动最大。", | |
| ) | |
| components[f"img2img_panel_{prefix}"] = img2img_panel | |
| with gr.Group(visible=False) as outpaint_panel: | |
| with gr.Row(): | |
| components[f"left_{prefix}"] = gr.Slider(0, 512, 64, step=64, label="向左扩展") | |
| components[f"right_{prefix}"] = gr.Slider(0, 512, 64, step=64, label="向右扩展") | |
| with gr.Row(): | |
| components[f"top_{prefix}"] = gr.Slider(0, 512, 64, step=64, label="向上扩展") | |
| components[f"bottom_{prefix}"] = gr.Slider(0, 512, 64, step=64, label="向下扩展") | |
| components[f"feathering_{prefix}"] = gr.Slider( | |
| 0, 100, 10, step=1, label="接缝羽化 / 蒙版外扩" | |
| ) | |
| components[f"outpaint_panel_{prefix}"] = outpaint_panel | |
| with gr.Group(visible=False) as hires_panel: | |
| with gr.Row(): | |
| components[f"hires_upscaler_{prefix}"] = gr.Dropdown( | |
| choices=["nearest-exact", "bilinear", "area", "bicubic", "bislerp"], | |
| value="nearest-exact", | |
| label="放大算法", | |
| ) | |
| components[f"hires_scale_by_{prefix}"] = gr.Slider( | |
| 1.0, 4.0, 1.5, step=0.1, label="放大倍数" | |
| ) | |
| components[f"hires_denoise_{prefix}"] = gr.Slider( | |
| 0.0, 1.0, 0.55, step=0.01, label="细节重绘幅度" | |
| ) | |
| components[f"hires_panel_{prefix}"] = hires_panel | |
| with gr.Group() as size_panel: | |
| with gr.Row(): | |
| components[f"aspect_ratio_{prefix}"] = gr.Dropdown( | |
| label="画幅", | |
| choices=list(default_resolution_map) or [default_aspect], | |
| value=default_aspect, | |
| interactive=True, | |
| scale=2, | |
| ) | |
| components[f"width_{prefix}"] = gr.Number( | |
| label="宽度", value=default_width, precision=0, interactive=True | |
| ) | |
| components[f"height_{prefix}"] = gr.Number( | |
| label="高度", value=default_height, precision=0, interactive=True | |
| ) | |
| components[f"size_panel_{prefix}"] = size_panel | |
| with gr.Accordion("高级采样与运行参数", open=False): | |
| with gr.Row(): | |
| components[f"sampler_{prefix}"] = gr.Dropdown( | |
| choices=SAMPLER_CHOICES, | |
| value=default_values.get("sampler_name", "euler"), | |
| label="采样器", | |
| ) | |
| components[f"scheduler_{prefix}"] = gr.Dropdown( | |
| choices=SCHEDULER_CHOICES, | |
| value=default_values.get("scheduler", "simple"), | |
| label="调度器", | |
| ) | |
| with gr.Row(): | |
| components[f"steps_{prefix}"] = gr.Slider( | |
| 1, 100, default_values.get("steps", 8), step=1, label="采样步数" | |
| ) | |
| components[f"cfg_{prefix}"] = gr.Slider( | |
| 1.0, 20.0, default_values.get("cfg", 1.0), step=0.1, label="CFG" | |
| ) | |
| with gr.Row(): | |
| components[f"seed_{prefix}"] = gr.Number( | |
| label="随机种子(-1 为随机)", value=-1, precision=0 | |
| ) | |
| components[f"batch_size_{prefix}"] = gr.Slider( | |
| 1, | |
| CONFIG.max_batch_size, | |
| 1, | |
| step=1, | |
| label="单次生成数量", | |
| info="数量越大,显存与 ZeroGPU 配额消耗越高。", | |
| ) | |
| with gr.Row(): | |
| components[f"clip_skip_{prefix}"] = gr.Slider( | |
| 1, 2, 1, step=1, label="Clip Skip", visible=False | |
| ) | |
| components[f"guidance_{prefix}"] = gr.Slider( | |
| 1.0, 10.0, 3.5, step=0.1, label="FLUX Guidance", visible=False | |
| ) | |
| components[f"zero_gpu_{prefix}"] = gr.Dropdown( | |
| choices=[("自动估算", 0), ("60 秒", 60), ("90 秒", 90), ("120 秒", 120)], | |
| value=0, | |
| label="ZeroGPU 运行时长", | |
| info="通常保持自动;复杂高分辨率任务可手动提高。", | |
| ) | |
| with gr.Row(): | |
| components[f"auto_model_params_{prefix}"] = gr.Checkbox( | |
| value=True, | |
| label="切模型时自动应用推荐采样参数", | |
| info="关闭后会保留你手调的步数、CFG、采样器和调度器。", | |
| scale=3, | |
| ) | |
| components[f"reset_model_params_{prefix}"] = gr.Button( | |
| "恢复当前模型推荐值", size="sm", scale=1 | |
| ) | |
| with gr.Column(scale=5, min_width=340, elem_id="result-column"): | |
| with gr.Row(): | |
| components[f"run_{prefix}"] = gr.Button( | |
| "开始生成", variant="primary", size="lg", scale=3 | |
| ) | |
| components[f"cancel_{prefix}"] = gr.Button( | |
| "取消排队", variant="stop", size="lg", scale=1 | |
| ) | |
| components[f"result_{prefix}"] = gr.Gallery( | |
| label="生成结果", | |
| show_label=True, | |
| columns=2, | |
| object_fit="contain", | |
| height=720, | |
| ) | |
| components[f"run_summary_{prefix}"] = gr.Markdown( | |
| "普通模式会在这里显示执行结果;PK/批量模式会逐项列出成功与失败。" | |
| ) | |
| components[f"clear_result_{prefix}"] = gr.Button("清空结果", size="sm") | |
| gr.Markdown( | |
| "生成结果包含 Prompt、参数和完整 ComfyUI 工作流元数据,下载 PNG 后可继续复现。", | |
| elem_classes="result-note", | |
| ) | |
| gr.Markdown("## 当前模型可用的扩展能力", elem_classes="advanced-title") | |
| gr.Markdown("下方只显示当前模型兼容的能力;切换模型后会自动更新。") | |
| components.update(create_lora_settings_ui(prefix)) | |
| components.update(create_controlnet_ui(prefix)) | |
| components.update(create_anima_controlnet_lllite_ui(prefix)) | |
| components.update(create_diffsynth_controlnet_ui(prefix)) | |
| components.update(create_krea2_controlnet_ui(prefix)) | |
| components.update(create_ipadapter_ui(prefix)) | |
| components.update(create_flux1_ipadapter_ui(prefix)) | |
| components.update(create_sd3_ipadapter_ui(prefix)) | |
| components.update(create_embedding_ui(prefix)) | |
| components.update(create_style_ui(prefix)) | |
| components.update(create_conditioning_ui(prefix)) | |
| with gr.Group() as native_reference_panel: | |
| gr.Markdown("原生参考槽位(兼容旧用法):仅普通文生图使用。参考图编辑 / 融合任务只读取上方图片列表;切换任务保留素材,但不混入本次生成。编号按有效图片预览为准。") | |
| components.update(create_reference_latent_ui(prefix)) | |
| components.update(create_hidream_o1_reference_ui(prefix)) | |
| components.update(create_joyai_reference_ui(prefix)) | |
| components.update(create_krea2_identity_edit_ui(prefix)) | |
| components.update(create_krea2_reference_edit_ui(prefix)) | |
| components.update(create_qwen_image_edit_ui(prefix)) | |
| components.update(create_boogu_edit_ui(prefix)) | |
| components.update(create_reference_image_ui(prefix)) | |
| components[f"native_reference_panel_{prefix}"] = native_reference_panel | |
| components.update(create_vae_override_ui(prefix)) | |
| components.update(create_pid_ui(prefix)) | |
| return components | |