import os import gradio as gr import json import logging import torch from PIL import Image import spaces from diffusers import DiffusionPipeline, AutoencoderTiny, AutoencoderKL, AutoPipelineForImage2Image from live_preview_helpers import calculate_shift, retrieve_timesteps, flux_pipe_call_that_returns_an_iterable_of_images from diffusers.utils import load_image from huggingface_hub import hf_hub_download, HfFileSystem, ModelCard, snapshot_download import copy import random import time # Load LoRAs from JSON file with open('loras.json', 'r') as f: loras = json.load(f) # Initialize the base model dtype = torch.bfloat16 device = "cuda" if torch.cuda.is_available() else "cpu" base_model = "black-forest-labs/FLUX.1-dev" taef1 = AutoencoderTiny.from_pretrained("madebyollin/taef1", torch_dtype=dtype).to(device) good_vae = AutoencoderKL.from_pretrained(base_model, subfolder="vae", torch_dtype=dtype).to(device) pipe = DiffusionPipeline.from_pretrained(base_model, torch_dtype=dtype, vae=taef1).to(device) pipe_i2i = AutoPipelineForImage2Image.from_pretrained(base_model, vae=good_vae, transformer=pipe.transformer, text_encoder=pipe.text_encoder, tokenizer=pipe.tokenizer, text_encoder_2=pipe.text_encoder_2, tokenizer_2=pipe.tokenizer_2, torch_dtype=dtype ) MAX_SEED = 2**32-1 pipe.flux_pipe_call_that_returns_an_iterable_of_images = flux_pipe_call_that_returns_an_iterable_of_images.__get__(pipe) class calculateDuration: def __init__(self, activity_name=""): self.activity_name = activity_name def __enter__(self): self.start_time = time.time() return self def __exit__(self, exc_type, exc_value, traceback): self.end_time = time.time() self.elapsed_time = self.end_time - self.start_time if self.activity_name: print(f"Elapsed time for {self.activity_name}: {self.elapsed_time:.6f} seconds") else: print(f"Elapsed time: {self.elapsed_time:.6f} seconds") def update_selection(evt: gr.SelectData, selected_indices, width, height): selected_index = evt.index selected_indices = selected_indices or [] if selected_index in selected_indices: # LoRA is already selected, remove it selected_indices.remove(selected_index) else: if len(selected_indices) < 2: selected_indices.append(selected_index) else: raise gr.Error("You can select up to 2 LoRAs only.") # Initialize outputs selected_info_1 = "" selected_info_2 = "" if len(selected_indices) >= 1: lora1 = loras[selected_indices[0]] selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨" if len(selected_indices) >= 2: lora2 = loras[selected_indices[1]] selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨" # Update prompt placeholder based on last selected LoRA if selected_indices: last_selected_lora = loras[selected_indices[-1]] new_placeholder = f"Type a prompt for {last_selected_lora['title']}" else: new_placeholder = "Type a prompt after selecting a LoRA" return ( gr.update(placeholder=new_placeholder), selected_info_1, selected_info_2, selected_indices, width, height, ) def remove_lora_1(selected_indices): selected_indices = selected_indices or [] if len(selected_indices) >= 1: selected_indices.pop(0) # Update selected_info_1 and selected_info_2 selected_info_1 = "" selected_info_2 = "" if len(selected_indices) >= 1: lora1 = loras[selected_indices[0]] selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨" if len(selected_indices) >= 2: lora2 = loras[selected_indices[1]] selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨" return selected_info_1, selected_info_2, selected_indices def remove_lora_2(selected_indices): selected_indices = selected_indices or [] if len(selected_indices) >= 2: selected_indices.pop(1) # Update selected_info_1 and selected_info_2 selected_info_1 = "" selected_info_2 = "" if len(selected_indices) >= 1: lora1 = loras[selected_indices[0]] selected_info_1 = f"### LoRA 1 Selected: [{lora1['title']}](https://huggingface.co/{lora1['repo']}) ✨" if len(selected_indices) >= 2: lora2 = loras[selected_indices[1]] selected_info_2 = f"### LoRA 2 Selected: [{lora2['title']}](https://huggingface.co/{lora2['repo']}) ✨" return selected_info_1, selected_info_2, selected_indices @spaces.GPU(duration=70) def generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress): pipe.to("cuda") generator = torch.Generator(device="cuda").manual_seed(seed) with calculateDuration("Generating image"): # Generate image for img in pipe.flux_pipe_call_that_returns_an_iterable_of_images( prompt=prompt_mash, num_inference_steps=steps, guidance_scale=cfg_scale, width=width, height=height, generator=generator, joint_attention_kwargs={"scale": 1.0}, output_type="pil", good_vae=good_vae, ): yield img @spaces.GPU(duration=70) def generate_image_to_image(prompt_mash, image_input_path, image_strength, steps, cfg_scale, width, height, seed): generator = torch.Generator(device="cuda").manual_seed(seed) pipe_i2i.to("cuda") image_input = load_image(image_input_path) final_image = pipe_i2i( prompt=prompt_mash, image=image_input, strength=image_strength, num_inference_steps=steps, guidance_scale=cfg_scale, width=width, height=height, generator=generator, joint_attention_kwargs={"scale": 1.0}, output_type="pil", ).images[0] return final_image def run_lora(prompt, image_input, image_strength, cfg_scale, steps, selected_indices, lora_scale_1, lora_scale_2, randomize_seed, seed, width, height, progress=gr.Progress(track_tqdm=True)): if not selected_indices: raise gr.Error("You must select at least one LoRA before proceeding.") selected_loras = [loras[idx] for idx in selected_indices] # Build the prompt with trigger words prompt_mash = prompt for lora in selected_loras: trigger_word = lora.get('trigger_word', '') if trigger_word: if lora.get("trigger_position") == "prepend": prompt_mash = f"{trigger_word} {prompt_mash}" else: prompt_mash = f"{prompt_mash} {trigger_word}" # Unload previous LoRA weights with calculateDuration("Unloading LoRA"): pipe.unload_lora_weights() pipe_i2i.unload_lora_weights() # Load LoRA weights with respective scales with calculateDuration("Loading LoRA weights"): for idx, lora in enumerate(selected_loras): lora_path = lora['repo'] scale = lora_scale_1 if idx == 0 else lora_scale_2 if image_input is not None: if "weights" in lora: pipe_i2i.load_lora_weights(lora_path, weight_name=lora["weights"], multiplier=scale) else: pipe_i2i.load_lora_weights(lora_path, multiplier=scale) else: if "weights" in lora: pipe.load_lora_weights(lora_path, weight_name=lora["weights"], multiplier=scale) else: pipe.load_lora_weights(lora_path, multiplier=scale) # Set random seed for reproducibility with calculateDuration("Randomizing seed"): if randomize_seed: seed = random.randint(0, MAX_SEED) # Generate image if image_input is not None: final_image = generate_image_to_image(prompt_mash, image_input, image_strength, steps, cfg_scale, width, height, seed) yield final_image, seed, gr.update(visible=False) else: image_generator = generate_image(prompt_mash, steps, seed, cfg_scale, width, height, progress) # Consume the generator to get the final image final_image = None step_counter = 0 for image in image_generator: step_counter+=1 final_image = image progress_bar = f'
"+trigger_word+"
as the trigger word" if trigger_word else "No trigger word found. If there's a trigger word, include it in your prompt"}