# Copyright (c) 2026 ByteDance Ltd. and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import gradio as gr import spaces import torch import os from PIL import Image from diffusers.utils import load_image # 导入你的两个 Pipeline from dreamlite import DreamLitePipeline from dreamlite import DreamLiteMobilePipeline from huggingface_hub import snapshot_download from transformers import CLIPFeatureExtractor from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker import numpy as np # ========================================== # 1. 全局配置与模型缓存管理 # ========================================== HF_TOKEN = os.environ.get("HF_TOKEN") device = "cpu" dtype = torch.bfloat16 # 加载 safety checker(启动时加载一次) safety_checker = StableDiffusionSafetyChecker.from_pretrained( "CompVis/stable-diffusion-safety-checker" ) feature_extractor = CLIPFeatureExtractor.from_pretrained( "openai/clip-vit-base-patch32" ) def check_safety(image): """检查生成的图像是否安全,返回 (image, is_nsfw)""" safety_input = feature_extractor(images=image, return_tensors="pt") np_image = np.array(image) _, has_nsfw = safety_checker( images=[np_image], clip_input=safety_input.pixel_values ) return has_nsfw[0] base_path = snapshot_download("carlofkl/DreamLite-base", token=HF_TOKEN) mobile_path = snapshot_download("carlofkl/DreamLite-mobile", token=HF_TOKEN) # 预加载两个模型到显存中,避免推理时动态加载 print("Loading DreamLite-base...") pipe_base = DreamLitePipeline.from_pretrained(base_path, torch_dtype=dtype).to(device) print("DreamLite-base Loaded Successfully!") print("Loading DreamLite-mobile...") pipe_mobile = DreamLiteMobilePipeline.from_pretrained(mobile_path, torch_dtype=dtype).to(device) print("DreamLite-mobile Loaded Successfully!") MODEL_CONFIGS = { "DreamLite-base": pipe_base, "DreamLite-mobile": pipe_mobile, } BASE_RESOLUTIONS = [ "1024 × 1024 (1:1)", "1152 × 896 (9:7)", "896 × 1152 (7:9)", "1216 × 832 (3:2)", "832 × 1216 (2:3)", "1344 × 768 (16:9)", "768 × 1344 (9:16)", ] def parse_resolution(res_str): """从分辨率字符串中解析宽高,例如 '1024 × 1024 (1:1)' -> (1024, 1024)""" parts = res_str.split("(")[0].strip().split("×") w = int(parts[0].strip()) h = int(parts[1].strip()) return w, h # ========================================== # 2. 定义推理函数 # ========================================== @spaces.GPU def generate_image( model_choice, prompt, image, resolution, num_inference_steps, guidance_scale, image_guidance_scale, seed ): # 从预加载的模型中选择 pipe = MODEL_CONFIGS[model_choice] # 强制将种子转为 Tensor Generator 以保证可复现 generator = torch.Generator(device="cpu").manual_seed(seed) # 将 Gradio 传入的图片 (如果有的话) 转换为 PIL 格式 input_image = image if image is not None else None if model_choice == "DreamLite-base": width, height = parse_resolution(resolution) else: # Mobile 版本固定 1024x1024 width, height = parse_resolution(resolution) if image is not None: width, height = image.size # 调用对应的 Pipeline out = pipe( prompt=prompt, image=input_image, width=width, height=height, guidance_scale=guidance_scale, image_guidance_scale=image_guidance_scale, num_inference_steps=num_inference_steps, generator=generator, ).images[0] if out.size != (width, height): out = out.resize((width, height), resample=Image.LANCZOS) # Safety Check if check_safety(out): raise gr.Error("⚠️ The generated image has been blocked by our safety filter. " "Please try a different prompt.") return out # ========================================== # 3. UI 联动:切换模型时更新参数面板 # ========================================== def on_model_change(model_choice): """ 切换模型时自动调整 UI 组件: - Base: 显示分辨率选择,默认 28 步 - Mobile: 隐藏分辨率选择(固定 1024×1024),默认 4 步 """ if model_choice == "DreamLite-base": return ( gr.update(visible=True, value="1024 × 1024 (1:1)"), # 分辨率选择可见 gr.update(value=28), # 默认 28 步 gr.update(value=3.5), # guidance scale ) else: return ( gr.update(visible=True, value="1024 × 1024 (1:1)"), # 分辨率选择隐藏 gr.update(value=4), # 默认 4 步 gr.update(value=1.0), # guidance scale ) # ========================================== # 4. 搭建 Gradio 页面 # ========================================== with gr.Blocks(title="DreamLite Demo") as demo: gr.Markdown("# 🌟 DreamLite: Efficient On-Device Generation and Editing") gr.Markdown("Select a model version, then generate images from text or upload an image to edit it based on instructions.") with gr.Row(): with gr.Column(): # 新增:模型选择下拉框 model_dropdown = gr.Dropdown( choices=list(MODEL_CONFIGS.keys()), value="DreamLite-base", # 默认选中 base label="Select Model Version", interactive=True ) # 输入组件 prompt_input = gr.Textbox(label="Prompt / Instruction", placeholder="e.g. A photo of a dog...", lines=3) image_input = gr.Image(type="pil", label="Input Image (Optional for Editing)") # 分辨率选择(仅 Base 版本可见) resolution_dropdown = gr.Dropdown( choices=BASE_RESOLUTIONS, value="1024 × 1024 (1:1)", label="Resolution (Base model only, Mobile fixed at 1024×1024)", interactive=True, visible=True ) with gr.Accordion("Advanced Options", open=False): steps_slider = gr.Slider(minimum=1, maximum=50, value=28, step=1, label="Inference Steps") guidance_slider = gr.Slider(minimum=0.0, maximum=20.0, value=3.5, step=0.1, label="Guidance Scale") img_guidance_slider = gr.Slider(minimum=0.0, maximum=5.0, value=1.0, step=0.1, label="Image Guidance Scale") seed_slider = gr.Slider(minimum=0, maximum=999999, value=42, step=1, label="Seed") submit_btn = gr.Button("Generate / Edit", variant="primary") with gr.Column(): # 输出组件 output_image = gr.Image(type="pil", label="Output Image") # 模型切换时联动更新 UI model_dropdown.change( fn=on_model_change, inputs=[model_dropdown], outputs=[resolution_dropdown, steps_slider, guidance_slider] ) # 绑定点击事件 (注意 inputs 列表增加了 model_dropdown 作为第一个参数) submit_btn.click( fn=generate_image, inputs=[model_dropdown, prompt_input, image_input, resolution_dropdown, steps_slider, guidance_slider, img_guidance_slider, seed_slider], outputs=[output_image] ) # 示例区 (同步加上对应的模型选择) gr.Examples( examples=[ ["DreamLite-base", "A close-up of a fire spitting dragon, cinematic shot.", None, "1216 × 832 (3:2)", 28, 3.5, 1.0, 123], ["DreamLite-mobile", "A portrait of a young woman with flowers.", None, "1024 × 1024 (1:1)", 4, 3.5, 1.0, 42], ["DreamLite-mobile", "Make it look like a pencil sketch", "assets/example.png", "1024 × 1024 (1:1)", 4, 1.0, 1.0, 42], ], inputs=[model_dropdown, prompt_input, image_input, resolution_dropdown, steps_slider, guidance_slider, img_guidance_slider, seed_slider] ) # ========================================== # 5. 启动应用 # ========================================== if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)