bildbearbeitung / app.py
Sebastiankay's picture
Update app.py
8c76ef9 verified
Raw
History Blame Contribute Delete
27.3 kB
import os
import sys
import logging
import spaces
import torch
import gradio as gr
import tempfile
import numpy as np
from datetime import datetime
from pathlib import Path
from PIL import Image
from typing import List, Tuple
from math import floor, ceil
import json
import base64
import io
import time
import random
import gc
import math
from huggingface_hub import InferenceClient
from diffusers import QwenImageEditPlusPipeline, FlowMatchEulerDiscreteScheduler
from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
from config_image_edit import TITLE, LOGO_HTML, CUSTOM_HEAD, HEADLINE_MD, SUBHEADLINE_MD, THEME, DEFAULT_PROMPT, PROMPT_PLACEHOLDER, DEFAULT_PROMPT_NEGATIVE, SYSTEM_PROMPT_EDIT, INFO_TAB_TEXT
log = logging.getLogger(__name__)
# MARK: GLOBAL CONSTANTS:
# Define paths using pathlib.Path for consistency
BASE_DIR = Path(__file__).resolve().parent
RES = BASE_DIR / "_res"
ASSETS = RES / "assets"
EXAMPLES = BASE_DIR / "examples"
IMAGE_CACHE = BASE_DIR / "image_cache"
# Ensure the image cache directory exists
IMAGE_CACHE.mkdir(exist_ok=True)
# Set static paths for Gradio
# gr.set_static_paths([str(IMAGE_CACHE), str(EXAMPLES), str(ASSETS), str(RES)])
gr.set_static_paths(paths=[IMAGE_CACHE, RES, EXAMPLES])
MAX_SEED = np.iinfo(np.int32).max
MIN_IMAGE_SIZE = 256
MAX_IMAGE_SIZE = 2048
# ------------------
# MARK: Pipeline load
# ------------------
scheduler_config = {
"base_image_seq_len": 256,
"base_shift": math.log(3),
"invert_sigmas": False,
"max_image_seq_len": 8192,
"max_shift": math.log(3),
"num_train_timesteps": 1000,
"shift": 1.0,
"shift_terminal": None,
"stochastic_sampling": False,
"time_shift_type": "exponential",
"use_beta_sigmas": False,
"use_dynamic_shifting": True,
"use_exponential_sigmas": False,
"use_karras_sigmas": False,
}
scheduler = FlowMatchEulerDiscreteScheduler.from_config(scheduler_config)
dtype = torch.bfloat16
device = "cuda" if torch.cuda.is_available() else "cpu"
# Load the model pipeline
pipe = QwenImageEditPlusPipeline.from_pretrained("Qwen/Qwen-Image-Edit-2511", scheduler=scheduler, torch_dtype=torch.bfloat16).to(device)
pipe.set_progress_bar_config(disable=None)
pipe.load_lora_weights("lightx2v/Qwen-Image-Edit-2511-Lightning", weight_name="Qwen-Image-Edit-2511-Lightning-8steps-V1.0-bf16.safetensors",adapter_name="lightning-8steps")
pipe.load_lora_weights("lightx2v/Qwen-Image-Edit-2511-Lightning", weight_name="Qwen-Image-Edit-2511-Lightning-4steps-V1.0-bf16.safetensors",adapter_name="lightning-4steps")
# Qwen-Image-Edit-Lightning-4steps-V1.0-bf16.safetensors
# pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multiple-angles", weight_name="镜头转换.safetensors", adapter_name="multiple-angles")
pipe.load_lora_weights("prithivMLmods/Qwen-Image-Edit-2511-Ultra-Realistic-Portrait", weight_name="URP_20.safetensors", adapter_name="ultra-realistic-portrait")
# pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Relight", weight_name="Qwen-Edit-Relight.safetensors", adapter_name="relight")
pipe.load_lora_weights("fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA", weight_name="qwen-image-edit-2511-multiple-angles-lora.safetensors", adapter_name="multiple-angles")
# pipe.load_lora_weights("tlennon-ie/qwen-edit-skin", weight_name="qwen-edit-skin_1.1_000002750.safetensors", adapter_name="edit-skin")
# pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509", weight_name="next-scene_lora-v2-3000.safetensors", adapter_name="next-scene")
pipe.load_lora_weights("valiantcat/Qwen-Image-Edit-2511-Upscale2K", weight_name="qwen_image_edit_2511_upscale.safetensors", adapter_name="upscale-image")
pipe.load_lora_weights("lilylilith/AnyPose", weight_name="2511-AnyPose-base-000006250.safetensors", adapter_name="anypose-base")
pipe.load_lora_weights("lilylilith/AnyPose", weight_name="2511-AnyPose-helper-00006000.safetensors", adapter_name="anypose-helper")
pipe.load_lora_weights("Alissonerdx/BFS-Best-Face-Swap", weight_name="bfs_head_v5_2511_original.safetensors", adapter_name="face-swap")
pipe.load_lora_weights("wiikoo/Qwen-lora-nsfw", weight_name="loras/qwen_image_edit_remove-clothing_v1.0.safetensors", adapter_name="remove-clothing")
pipe.load_lora_weights("wiikoo/Qwen-lora-nsfw", weight_name="loras/Qwen-NSFW-Beta5.safetensors", adapter_name="qwen-nsfw")
# "Qwen_NSFW_Beta5" "loras/Qwen-NSFW-Beta5.safetensors",
# pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
# pipe.fuse_lora()
def normalize_images(image_data) -> List[Image.Image]:
"""
Erwartet eine Liste von Einträgen, die entweder
- ein PIL‑Bild,
- ein Tupel (PIL‑Bild, Beschreibung) oder
- ein Tupel (Pfad, Beschreibung)
sein können. Gibt eine Liste von PIL‑Bildern zurück,
die alle auf die gleiche Größe zugeschnitten sind.
"""
MAX_HEIGHT = 2560
MAX_WIDTH = 1704
# 1. Alle Eingaben in PIL‑Bilder umwandeln
images = []
for item in image_data:
if isinstance(item, tuple):
img_candidate = item[0] # erstes Element ist Bild oder Pfad
else:
img_candidate = item
if isinstance(img_candidate, str):
img = Image.open(img_candidate)
elif hasattr(img_candidate, 'save'): # PIL‑Bild
img = img_candidate
else:
continue # oder raise Exception
images.append({
'image': img,
'width': img.width,
'height': img.height,
'aspect_ratio': img.width / img.height
})
if not images:
return []
# 2. Referenzgröße bestimmen (Bild mit minimaler Höhe, wie ursprünglich)
min_aspect_img = min(images, key=lambda x: x['height'])
target_width = min_aspect_img['width']
target_width = floor(target_width / 2) * 2
target_height = min_aspect_img['height']
target_height = floor(target_height / 2) * 2
target_aspect = target_width / target_height
# 3. Begrenzung der Zielgröße (wie im Original)
if target_width > target_height:
target_height = min(target_height, 1704)
target_width = floor((int(target_height * target_aspect) / 2)) * 2
else:
target_height = min(target_height, 1248)
target_width = floor((int(target_height * target_aspect) / 2)) * 2
# 4. Alle Bilder skalieren und zuschneiden
output_images = []
for img_data in images:
img = img_data['image']
img_aspect = img.width / img.height
if img_aspect > target_aspect:
# Bild ist breiter → nach Höhe skalieren
new_height = min(target_height, MAX_HEIGHT)
new_width = int(new_height * img_aspect)
else:
# Bild ist höher → nach Breite skalieren
new_width = min(target_width, MAX_WIDTH)
new_height = int(new_width / img_aspect)
img_resized = img.resize((new_width, new_height), Image.LANCZOS)
# Zentrierten Ausschnitt berechnen
left = (new_width - target_width) // 2
top = (new_height - target_height) // 2
right = left + target_width
bottom = top + target_height
img_cropped = img_resized.crop((left, top, right, bottom))
output_images.append(img_cropped.convert("RGB"))
return output_images
def polish_prompt_hf(original_prompt, img_list):
# Ensure HF_TOKEN is set
api_key = os.environ.get("HF_TOKEN")
if not api_key:
print("Warning: HF_TOKEN not set. Falling back to original prompt.")
return original_prompt
prompt = f"{SYSTEM_PROMPT_EDIT}\n\nUser Input: {original_prompt}\n\nRewritten Prompt:"
system_prompt = "you are a helpful assistant, you should provide useful answers to users."
try:
# Initialize the client
client = InferenceClient(
provider="nebius",
api_key=api_key,
)
# Convert list of images to base64 data URLs
image_urls = []
if img_list is not None:
# Ensure img_list is actually a list
if not isinstance(img_list, list):
img_list = [img_list]
for img in img_list:
image_url = None
# If img is a PIL Image
if hasattr(img, 'save'): # Check if it's a PIL Image
buffered = io.BytesIO()
img.save(buffered, format="PNG")
img_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
image_url = f"data:image/png;base64,{img_base64}"
# If img is already a file path (string)
elif isinstance(img, str):
with open(img, "rb") as image_file:
img_base64 = base64.b64encode(image_file.read()).decode('utf-8')
image_url = f"data:image/png;base64,{img_base64}"
else:
print(f"Warning: Unexpected image type: {type(img)}, skipping...")
continue
if image_url:
image_urls.append(image_url)
# Build the content array with text first, then all images
content = [
{
"type": "text",
"text": prompt
}
]
# Add all images to the content
for image_url in image_urls:
content.append({
"type": "image_url",
"image_url": {
"url": image_url
}
})
# Format the messages for the chat completions API
messages = [
{"role": "system", "content": system_prompt},
{
"role": "user",
"content": content
}
]
# Call the API
completion = client.chat.completions.create(
model="Qwen/Qwen2.5-VL-72B-Instruct",
messages=messages,
)
# Parse the response
result = completion.choices[0].message.content
# Try to extract JSON if present
if '"Rewritten"' in result:
try:
# Clean up the response
result = result.replace('```json', '').replace('```', '')
result_json = json.loads(result)
polished_prompt = result_json.get('Rewritten', result)
except:
polished_prompt = result
else:
polished_prompt = result
polished_prompt = polished_prompt.strip().replace("\n", " ")
return polished_prompt
except Exception as e:
print(f"Error during API call to Hugging Face: {e}")
# Fallback to original prompt if enhancement fails
return original_prompt
def use_history_as_input(evt: gr.SelectData, history):
if history and evt.index < len(history):
im = history[evt.index][0]
image_path = f"image_cache/{history[evt.index][1]}"
im.save(image_path, format="PNG")
return image_path # gr.update(value=history[evt.index][0])
return # gr.update()
@spaces.GPU(duration=60)
def infer(
images,
prompt,
lora_adapter="Lightning-8steps",
negative_prompt=" ",
num_inference_steps=30,
true_guidance_scale=2.0,
seed=42,
randomize_seed=False,
rewrite_prompt=False,
gallery=None,
height=None,
width=None,
num_images_per_prompt=1,
progress=gr.Progress(track_tqdm=True),
):
if true_guidance_scale <= 2:
negative_prompt = " "
if randomize_seed:
seed = random.randint(0, MAX_SEED)
if lora_adapter == "Multiple-Angles": pipe.set_adapters(["lightning-8steps", "multiple-angles"], adapter_weights=[1.0, 1.0])
elif lora_adapter == "Ultra-Realistic-Portrait": pipe.set_adapters(["ultra-realistic-portrait", "lightning-8steps"], adapter_weights=[1.0, 1.0])
# elif lora_adapter == "Relight": pipe.set_adapters(["relight"], adapter_weights=[1.0])
# elif lora_adapter == "Multi-Angle-Lighting": pipe.set_adapters(["multi-angle-lighting"], adapter_weights=[1.0])
# elif lora_adapter == "Edit-Skin": pipe.set_adapters(["edit-skin"], adapter_weights=[1.0])
# elif lora_adapter == "Next-Scene": pipe.set_adapters(["next-scene"], adapter_weights=[1.0])
elif lora_adapter == "Upscale-Image": pipe.set_adapters(["lightning-8steps", "upscale-image"], adapter_weights=[1.0, 1.0])
elif lora_adapter == "Any-Pose":
pipe.set_adapters(["lightning-8steps", "anypose-base", "anypose-helper"], adapter_weights=[1.0, 0.7, 0.7])
elif lora_adapter == "Face-Swap":
pipe.set_adapters(["lightning-8steps", "face-swap"], adapter_weights=[1.0, 0.9])
elif lora_adapter == "Face-Swap-4-steps":
pipe.set_adapters(["lightning-4steps", "face-swap"], adapter_weights=[1.0, 0.9])
elif lora_adapter == "Undress":
pipe.set_adapters(["lightning-8steps", "remove-clothing", "qwen-nsfw"], adapter_weights=[1.0, 0.9, 0.9])
elif lora_adapter == "Undress-4steps":
pipe.set_adapters(["lightning-4steps", "remove-clothing", "qwen-nsfw"], adapter_weights=[1.0, 0.9, 0.9])
elif lora_adapter == "Lightning-4steps": pipe.set_adapters(["lightning-4steps"], adapter_weights=[1.0])
elif lora_adapter == "Lightning-8steps": pipe.set_adapters(["lightning-8steps"], adapter_weights=[1.0])
generator = torch.Generator(device=device).manual_seed(seed)
# Load input images into PIL Images
_norm_images = normalize_images(images)
pil_images = _norm_images
# if images is not None:
# for item in _norm_images:
# try:
# if isinstance(item[0], Image.Image):
# pil_images.append(item[0].convert("RGB"))
# elif isinstance(item[0], str):
# pil_images.append(Image.open(item[0]).convert("RGB"))
# elif hasattr(item, "name"):
# pil_images.append(Image.open(item.name).convert("RGB"))
# except Exception:
# continue
if height==256 and width==256:
height, width = None, None
print(f"Calling pipeline with prompt: '{prompt}'")
print(f"Negative Prompt: '{negative_prompt}'")
print(f"Seed: {seed}, Steps: {num_inference_steps}, Guidance: {true_guidance_scale}, Size: {width}x{height}")
# if rewrite_prompt and len(pil_images) > 0:
# prompt = polish_prompt_hf(prompt, pil_images)
# print(f"Rewritten Prompt: {prompt}")
# Generate the image
image = pipe(
image=pil_images if len(pil_images) > 0 else None,
prompt=prompt,
height=height,
width=width,
negative_prompt=negative_prompt,
num_inference_steps=num_inference_steps,
generator=generator,
true_cfg_scale=true_guidance_scale,
num_images_per_prompt=num_images_per_prompt,
).images[0]
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
image_path = IMAGE_CACHE / f"{timestamp}.png"
try:
image.save(image_path, format="PNG")
except Exception as exc:
raise gr.Error(f"Fehler beim Speichern des Bildes: {exc}")
if gallery is None:
gallery = []
gallery.insert(0, (image, str(f"{timestamp}.png")))
return str(image_path), seed, gallery
# ------------------
# MARK: GRADIO UI
# ------------------
with gr.Blocks(title=TITLE) as demo:
_PROPMT_STATE = gr.State(value={'PREPROMPT': "", 'PROMPT': "", 'LORA': ""})
with gr.Row(elem_classes="row-logo"):
gr.HTML(
f"""{LOGO_HTML}""",
elem_classes="logo-html",
)
with gr.Tab(" Start"):
with gr.Row(elem_classes="row-header"):
gr.HTML(
f"""<center>
<h2 class="headline">{HEADLINE_MD}</h2>
<h3 class="sub-headline">{SUBHEADLINE_MD}</h3>
<p class="like-request">lg Sebastian <img id="wink" src='/gradio_api/file=_res/wink.svg' width="20" /> gib dem Space gerne ein <img id="heart" src='/gradio_api/file=_res/heart.svg' width="20"/></p>
</center>
""",
elem_classes="md-header",
)
with gr.Row(elem_classes="row-main"):
with gr.Column(elem_classes="col-input") as input_column:
# INPUT DATA COLUMN:
with gr.Column(elem_classes="storyboard-column"):
with gr.Row(elem_classes="gradio-row storyboard-row", equal_height=True):
with gr.Column():
gr.Markdown("# **** Eingabe Bilder", elem_classes="markdown-label")
input_image_component = gr.Gallery(type="pil", label="Bilder", show_label=True, allow_preview=False, object_fit="cover", elem_classes="storyboard-image image-1", interactive=True)
gr.HTML("""<i class="fa-solid fa-arrow-right"></i>""", elem_classes="storyboard-arrow")
with gr.Column():
gr.Markdown("# **** Prompt", elem_classes="markdown-label")
prompt = gr.Textbox(value=DEFAULT_PROMPT, placeholder=PROMPT_PLACEHOLDER, label="Regieanweisung", show_label=False, elem_classes="regieanweisung-textbox", lines=10, max_lines=12, interactive=True, html_attributes=gr.InputHTMLAttributes(autocorrect="off", spellcheck=False))
with gr.Row(elem_classes="gradio-row"):
lora_adapter = gr.Dropdown(
choices=[
("Standard Modus", "Lightning-8steps"),
("Lightning 4 Schritte", "Lightning-4steps"),
("Jede Pose", "Any-Pose"),
("Face Swap", "Face-Swap"),
("Face Swap 4 Schritte", "Face-Swap-4steps"),
("Upscale-Image", "Upscale-Image"),
("Multiple-Angles", "Multiple-Angles"),
("Realistisches Porträt", "Ultra-Realistic-Portrait"),
("Undress", "Undress"),
("Undress 4 Schritte", "Undress-4steps")
],
value="Lightning-8steps",
elem_classes="lora-adapter-dropdown",
label="⚗️ Voreinstellungen",
info="Wähle eine Voreinstellung für gezielte hochwertige Bearbeitung.",
interactive=True
)
steps_slider = gr.Slider(
minimum=1,
maximum=30,
step=1,
value=8,
label="🚶‍➡️ Inferenzschritte",
info="Anzahl der Iterationen, die das Modell zur Bildgenerierung durchläuft; mehr Schritte erhöhen Detailtreue, verlangsamen aber die Berechnung.",
interactive=True,
elem_classes="einstellungen-slider einstellungen-steps",
)
with gr.Column(elem_classes="profi-einstellungen-column"):
with gr.Accordion("⚙️ Profi-Einstellungen", elem_classes="profi-einstellungen-accordion", open=False):
with gr.Row(elem_classes="profi-einstellungen-inner-row"):
with gr.Column(elem_classes="profi-einstellungen-inner-column"):
gr.Markdown("# **** Negative Anweisungen", elem_classes="markdown-label")
negative_prompt_input = gr.Textbox(value=DEFAULT_PROMPT_NEGATIVE, label="Profi-Name", show_label=False, elem_classes="negative-prompt-textbox", lines=10, interactive=False, html_attributes=gr.InputHTMLAttributes(autocorrect="off", spellcheck=False))
with gr.Column(elem_classes="profi-einstellungen-inner-column"):
with gr.Row(elem_classes="einstellungen-seed-row"):
seed_input = gr.Number(value=42, minimum=0, maximum=MAX_SEED, step=1, label="🌱 Seed", info="Ein fester Ausgangswert, der die Zufallszahlen im Bildgenerierungsprozess steuert, damit das gleiche Ergebnis bei gleicher Eingabe reproduzierbar ist.", elem_classes="einstellungen-seed", elem_id="seed_input", interactive=False)
randomize_seed_checkbox = gr.Checkbox(value=True, label="Zufallsgenerator", show_label=False, elem_classes="einstellungen-random-seed", interactive=True)
guidance_scale_input = gr.Slider(
minimum=0.0,
maximum=10.0,
step=0.1,
value=2,
label="🧐 Leitwert",
info="Steuert, wie stark das Modell dem Prompt folgt; höhere Werte führen zu genauerer Bildgestaltung.",
interactive=True,
elem_classes="einstellungen-slider einstellungen-guidance-scale-1",
)
rewrite_prompt = gr.Checkbox(label="✨ Prompt verbessern", value=False, elem_classes="einstellungen-rewrite-prompt", interactive=True)
game_button = gr.Button("Bearbeiten ✨", variant="primary", elem_classes="gradio-button run-button", elem_id="gameBtn", size="lg")
generate_button = gr.Button("Bearbeiten ✨", variant="primary", elem_classes="gradio-button run-button", elem_id="runBtn", size="lg")
with gr.Column(elem_classes="output-column", visible=False) as output_column_1:
with gr.Row(elem_classes="gradio-row", equal_height=True):
with gr.Column():
gr.Markdown("# **** Ergebnis", elem_classes="markdown-label")
result_image = gr.Image(label="Ergebnis", type="pil", show_label=False, buttons=["download", "fullscreen"], elem_classes="result-image", visible=True, interactive=False)
with gr.Column():
gr.Markdown("# **** Verlauf", elem_classes="markdown-label")
result_history = gr.Gallery([], label="Ergebnis", show_label=False, buttons=["download", "fullscreen"], object_fit="cover", elem_classes="result-gallery", interactive=False, allow_preview=False, type="pil")
with gr.Tab(" Info", elem_classes="info-tab"):
with gr.Column(elem_classes="info-column"):
gr.Markdown(INFO_TAB_TEXT)
randomize_seed_checkbox.change(fn=lambda x: gr.update(interactive=(not x)), inputs=[randomize_seed_checkbox], outputs=[seed_input], show_progress=False)
guidance_scale_input.change(fn=lambda x: gr.update(interactive=(x > 2)), inputs=[guidance_scale_input], outputs=[negative_prompt_input], show_progress=False)
result_history.select(fn=use_history_as_input, inputs=[result_history], outputs=[result_image], show_progress=False)
ui_inputs = [input_image_component, prompt, lora_adapter, negative_prompt_input, steps_slider, guidance_scale_input, seed_input, randomize_seed_checkbox, rewrite_prompt, result_history]
generate_button.click(fn=lambda: gr.Column(visible=True), outputs=[output_column_1], show_progress=False, scroll_to_output=True).then(fn=infer, inputs=ui_inputs, outputs=[result_image, seed_input, result_history], show_progress_on=[result_image, result_history], scroll_to_output=True).then(
fn=None, outputs=generate_button, js="() => { document.getElementById('gameBtn').classList.remove('process-running'); }"
)
def _remove(rem, string, replace=""):
return re.sub(f".*{rem}\n?", replace, string, flags=re.S)
def _lora_adapter_change(lora_adapter_input, prompt_input, _PROPMT_STATE_INPUT):
ANY_POSE_PREPROMPT = """Make the person in image 1 do the exact same pose of the person in image 2.
Changing the style and background of the image of the person in image 1 is undesirable, so don't do it.
The new pose should be pixel accurate to the pose we are trying to copy.
The position of the arms and head and legs should be the same as the pose we are trying to copy.
Change the field of view and angle to match exactly image 2. Head tilt and eye gaze pose should match the person in image 2.
Remove the background of image 2, and replace it with the background of image 1.
Don't change the identity of the person in image 1, keep their appearance the same, it is undesirable to change their facical features or hair style. don't do it.\n
"""
ANY_POSE_PREPROMPT = ANY_POSE_PREPROMPT.replace(" ", "")
FACE_SWAP_PREPROMPT = """head_swap: start with Picture 1 as the base image, keeping its lighting, environment, and background. Remove the head from Picture 1 completely and replace it with the head from Picture 2.
FROM PICTURE 1 (strictly preserve):
- Scene: lighting conditions, shadows, highlights, color temperature, environment, background
- Head positioning: exact rotation angle, tilt, direction the head is facing
- Expression: facial expression, micro-expressions, eye gaze direction, mouth position, emotion
FROM PICTURE 2 (strictly preserve identity):
- Facial structure: face shape, bone structure, jawline, chin
- All facial features: eye color, eye shape, nose structure, lip shape and fullness, eyebrows
- Hair: color, style, texture, hairline
- Skin: texture, tone, complexion
The replaced head must seamlessly match Picture 1's lighting and expression while maintaining the complete identity from Picture 2. High quality, photorealistic, sharp details, 4k.\n
"""
if _PROPMT_STATE_INPUT['PROMPT'] == "" and prompt_input != "":
_PROPMT_STATE_INPUT['PROMPT'] = prompt_input
if lora_adapter_input == "Any-Pose":
_PROPMT_STATE_INPUT['PREPROMPT'] = ANY_POSE_PREPROMPT
_PROPMT_STATE_INPUT['PROMPT'] = prompt_input
return _PROPMT_STATE_INPUT
if lora_adapter_input == "Face-Swap":
_PROPMT_STATE_INPUT['PREPROMPT'] = FACE_SWAP_PREPROMPT
_PROPMT_STATE_INPUT['PROMPT'] = prompt_input
return _PROPMT_STATE_INPUT
_PROPMT_STATE_INPUT['PREPROMPT'] = ""
return _PROPMT_STATE_INPUT
lora_adapter.change(fn=_lora_adapter_change, inputs=[lora_adapter, prompt, _PROPMT_STATE], outputs=[_PROPMT_STATE], show_progress=False)
lora_adapter.change(lambda x: gr.update(value=4 if x == "Lightning-4steps" else 8), inputs=[lora_adapter], outputs=[steps_slider], show_progress=False)
_PROPMT_STATE.change(lambda x: gr.update(value=f"{x['PREPROMPT']}{x['PROMPT']}"), inputs=[_PROPMT_STATE], outputs=[prompt], show_progress=False)
if __name__ == "__main__":
demo.launch(theme=THEME, head=CUSTOM_HEAD, css_paths=["_res/_custom_image_edit.css", "_res/miniGameButton.css"], footer_links=["gradio", "settings"])