appinitdev commited on
Commit
ec8560d
·
verified ·
1 Parent(s): f360ccb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -101
app.py CHANGED
@@ -1,138 +1,83 @@
1
- import os
2
- import torch
3
- import math
4
  import gradio as gr
 
5
  from PIL import Image
6
- from diffusers import QwenImageEditPlusPipeline, FlowMatchEulerDiscreteScheduler
7
- from huggingface_hub import WebhooksServer
8
-
9
- # Configuración de variables globales del sistema
10
- BASE_MODEL = "prithivMLmods/Qwen-Image-Edit-AIO-FP8"
11
- LORA_COSPLAY = "joyfox/Qwen-Image-Edit-Cosplay"
12
- LORA_LIGHTNING = "lightx2v/Qwen-Image-Lightning"
13
 
14
- # Inicialización de la configuración del planificador para pocos pasos de inferencia
15
- scheduler_config = {
16
- "base_image_seq_len": 256,
17
- "invert_sigmas": False,
18
- "max_image_seq_len": 8192,
19
- "max_shift": math.log(3),
20
- "num_train_timesteps": 1000,
21
- "shift": 1.0,
22
- "shift_terminal": None,
23
- "stochastic_sampling": False,
24
- "time_shift_type": "exponential",
25
- "use_beta_sigmas": False,
26
- "use_dynamic_shifting": True,
27
- "use_exponential_sigmas": False,
28
- "use_karras_sigmas": False,
29
- }
30
 
31
- print("Cargando planificador de flujo de acoplamiento...")
32
- scheduler = FlowMatchEulerDiscreteScheduler.from_config(scheduler_config)
33
-
34
- print("Inicializando tubería multireferencia QwenImageEditPlusPipeline...")
35
- pipe = QwenImageEditPlusPipeline.from_pretrained(
36
- BASE_MODEL,
37
- scheduler=scheduler,
38
- torch_dtype=torch.bfloat16,
39
- low_cpu_mem_usage=True # <-- AÑADIDO: Previene el colapso OOM de la RAM del sistema
40
  )
41
 
42
- # ELIMINADO: pipe.to("cuda") (Forzaba todo el modelo a la GPU de golpe)
43
- # AÑADIDO: Descarga inteligente entre CPU y GPU para ahorrar VRAM
44
  pipe.enable_model_cpu_offload()
45
 
46
- # Diccionario para controlar el estado de carga perezosa de la LoRA de cosplay
47
- loaded_adapters = {}
48
-
49
- def load_cosplay_adapters_on_demand():
50
- """Carga de forma perezosa el adaptador LoRA de cosplay para optimizar la memoria"""
51
- if "cosplay" not in loaded_adapters:
52
- print("Carga perezosa activada: Descargando pesos de joyfox/Qwen-Image-Edit-Cosplay...")
53
- pipe.load_lora_weights(LORA_COSPLAY, adapter_name="cosplay")
54
-
55
- print("Cargando adaptador de velocidad Qwen-Image-Lightning...")
56
- pipe.load_lora_weights(
57
- LORA_LIGHTNING,
58
- weight_name="Qwen-Image-Lightning-8steps-V1.0.safetensors",
59
- adapter_name="lightning"
60
- )
61
-
62
- # Establecemos los pesos de fusión óptimos entre la velocidad y la especialización
63
- pipe.set_adapters(["cosplay", "lightning"], adapter_weights=[0.85, 1.0])
64
- loaded_adapters["cosplay"] = True
65
- print("Adaptadores fusionados y listos en GPU.")
66
 
67
- def process_cosplay_edit(base_image, reference_image, prompt, steps, cfg, seed):
 
 
68
  if base_image is None or reference_image is None:
69
- raise gr.Error("Es obligatorio proporcionar tanto la imagen humana base como la referencia de anime.")
70
 
71
- # Garantizar la carga del adaptador únicamente cuando se solicita la inferencia
72
- load_cosplay_adapters_on_demand()
73
-
74
- # Redimensionamiento de las imágenes manteniendo la coherencia de dimensiones múltiples de 8
75
- width, height = base_image.size
76
- max_dimension = 1024
77
- if max(width, height) > max_dimension:
78
- factor = max_dimension / max(width, height)
79
- width = int((width * factor) // 8) * 8
80
- height = int((height * factor) // 8) * 8
81
- else:
82
- width = int(width // 8) * 8
83
- height = int(height // 8) * 8
84
-
85
- base_resized = base_image.resize((width, height), Image.Resampling.LANCZOS)
86
- ref_resized = reference_image.resize((width, height), Image.Resampling.LANCZOS)
87
 
88
  generator = torch.Generator("cuda").manual_seed(int(seed))
89
 
90
- # Inferencia sin seguimiento de gradiente para liberar caché de la GPU activamente
91
  with torch.inference_mode():
92
  output = pipe(
93
- image=[base_resized, ref_resized],
94
  prompt=prompt,
95
- negative_prompt=" ",
96
- width=width,
97
- height=height,
98
  num_inference_steps=int(steps),
99
- true_cfg_scale=float(cfg),
100
  generator=generator
101
  )
102
 
103
- return output.images
104
 
105
- # Construcción de la interfaz gráfica y de la API de backend de Gradio
106
- # delete_cache=(300, 300) limpia archivos temporales cada 5 minutos
107
- with gr.Blocks(delete_cache=(300, 300), theme=gr.themes.Default()) as demo:
108
- gr.Markdown("# **Estudio de Transferencia de Vestimenta Cosplay (Qwen-Image-Edit)**")
109
- gr.Markdown("Servicio REST y de interfaz para la clonación semántica de atuendos anime sobre personas reales.")
110
 
111
  with gr.Row():
112
  with gr.Column():
113
- base_input = gr.Image(label="Persona Real (Imagen 1)", type="pil")
114
- ref_input = gr.Image(label="Personaje de Anime (Imagen 2)", type="pil")
115
  prompt_input = gr.Textbox(
116
- label="Instrucción de Edición Semántica",
117
- value="把图2中动漫人物中的发型,服饰和装扮道具迁移到图1的真实人物,图1真实人物保持高度人脸一致性",
118
  lines=3
119
  )
120
- with gr.Accordion("Parámetros del Transformador", open=False):
121
- inference_steps = gr.Slider(minimum=4, maximum=24, value=8, step=1, label="Pasos de Inferencia (Lightning)")
122
- cfg_scale = gr.Slider(minimum=1.0, maximum=8.0, value=1.5, step=0.5, label="True CFG Scale")
123
- seed_num = gr.Number(value=1337, label="Semilla Aleatoria")
124
 
125
- generate_btn = gr.Button("Ejecutar Edición", variant="primary")
126
 
127
  with gr.Column():
128
- output_display = gr.Image(label="Imagen Resultante")
129
 
130
  generate_btn.click(
131
  fn=process_cosplay_edit,
132
- inputs=[base_input, ref_input, prompt_input, inference_steps, cfg_scale, seed_num],
133
  outputs=output_display
134
  )
135
 
136
- # Inicializar la aplicación de Gradio
137
- demo.queue()
138
- demo.launch()
 
 
 
 
1
  import gradio as gr
2
+ import torch
3
  from PIL import Image
4
+ from diffusers import StableDiffusionXLImg2ImgPipeline
5
+ import spaces
 
 
 
 
 
6
 
7
+ # 1. Definición del modelo súper ligero (Versión FP16 que pesa ~6.5GB)
8
+ MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ print("Descargando e inicializando SDXL FP16...")
11
+ pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained(
12
+ MODEL_ID,
13
+ torch_dtype=torch.float16,
14
+ variant="fp16",
15
+ use_safetensors=True
 
 
 
16
  )
17
 
18
+ # 2. Descarga del modelo a CPU para ahorrar VRAM
 
19
  pipe.enable_model_cpu_offload()
20
 
21
+ # 3. Cargamos IP-Adapter (El puente que transfiere la ropa del anime a la persona)
22
+ print("Cargando IP-Adapter para transferencia de estilo...")
23
+ pipe.load_ip_adapter("h94/IP-Adapter", subfolder="sdxl_models", weight_name="ip-adapter_sdxl.safetensors")
24
+ # Ajustamos la fuerza con la que el anime afectará la foto real (0.0 a 1.0)
25
+ pipe.set_ip_adapter_scale(0.65)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ # El decorador @spaces.GPU le dice a Hugging Face que te preste una A100 gratis por unos segundos
28
+ @spaces.GPU
29
+ def process_cosplay_edit(base_image, reference_image, prompt, steps, strength, seed):
30
  if base_image is None or reference_image is None:
31
+ raise gr.Error("Es obligatorio proporcionar ambas imágenes.")
32
 
33
+ # Redimensionar para SDXL (optimizado para 1024x1024)
34
+ base_resized = base_image.resize((1024, 1024), Image.Resampling.LANCZOS)
35
+ ref_resized = reference_image.resize((1024, 1024), Image.Resampling.LANCZOS)
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  generator = torch.Generator("cuda").manual_seed(int(seed))
38
 
39
+ # La Inferencia
40
  with torch.inference_mode():
41
  output = pipe(
 
42
  prompt=prompt,
43
+ image=base_resized, # La foto de la persona real (Estructura base)
44
+ ip_adapter_image=ref_resized, # La imagen del anime (Transferencia de estilo/ropa)
45
+ strength=float(strength), # Cuánto permitimos que cambie la foto original
46
  num_inference_steps=int(steps),
47
+ guidance_scale=7.5,
48
  generator=generator
49
  )
50
 
51
+ return output.images[0]
52
 
53
+ # --- Interfaz de Gradio ---
54
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
55
+ gr.Markdown("# **Estudio de Transferencia Cosplay (Modo Ligero - SDXL)**")
56
+ gr.Markdown("Ecosistema optimizado al 100% para el nivel gratuito de Hugging Face.")
 
57
 
58
  with gr.Row():
59
  with gr.Column():
60
+ base_input = gr.Image(label="Persona Real (Base)", type="pil")
61
+ ref_input = gr.Image(label="Personaje de Anime (Estilo/Ropa)", type="pil")
62
  prompt_input = gr.Textbox(
63
+ label="Instrucción",
64
+ value="masterpiece, best quality, highly detailed, realistic person wearing the exact cosplay outfit from the reference image, perfect face, cinematic lighting",
65
  lines=3
66
  )
67
+ with gr.Accordion("Parámetros Avanzados", open=False):
68
+ inference_steps = gr.Slider(minimum=10, maximum=50, value=25, step=1, label="Pasos de Inferencia")
69
+ strength_scale = gr.Slider(minimum=0.1, maximum=1.0, value=0.75, step=0.05, label="Fuerza de Transformación (Strength)")
70
+ seed_num = gr.Number(value=42, label="Semilla Aleatoria")
71
 
72
+ generate_btn = gr.Button("Ejecutar Transferencia", variant="primary")
73
 
74
  with gr.Column():
75
+ output_display = gr.Image(label="Resultado Final")
76
 
77
  generate_btn.click(
78
  fn=process_cosplay_edit,
79
+ inputs=[base_input, ref_input, prompt_input, inference_steps, strength_scale, seed_num],
80
  outputs=output_display
81
  )
82
 
83
+ demo.queue().launch()