cobramv12 commited on
Commit
b70cde5
Β·
verified Β·
1 Parent(s): 5dfe183

Update: Ultra Realistic Model + Dynamic LoRA loader

Browse files
Files changed (1) hide show
  1. app.py +81 -179
app.py CHANGED
@@ -4,238 +4,140 @@ import torch
4
  import numpy as np
5
  from PIL import Image
6
  import tempfile, os
 
7
 
8
- # ─── MODELOS ───────────────────────────────────────────────────────────────────
9
- TEXT2IMG_MODEL = "SG161222/RealVisXL_V4.0" # Realista, sin censura
10
- IMG2IMG_MODEL = "SG161222/RealVisXL_V4.0"
11
- LTX_MODEL = "Lightricks/LTX-Video"
12
- LTX_LORA = "Lora-Daddy/Ltx2.3-real-nudity-early-alpha-30k-steps"
 
13
 
14
- pipe_t2i = None
15
- pipe_i2i = None
16
  pipe_video = None
17
 
18
- NEG_DEFAULT = (
19
- "censored, blurry, low quality, bad anatomy, deformed, ugly, "
20
- "watermark, logo, text, worst quality, jpeg artifacts"
21
- )
22
 
23
  # ─── LOADERS ───────────────────────────────────────────────────────────────────
24
- def load_t2i():
25
  global pipe_t2i
 
26
  if pipe_t2i is None:
27
- from diffusers import StableDiffusionXLPipeline
28
  pipe_t2i = StableDiffusionXLPipeline.from_pretrained(
29
- TEXT2IMG_MODEL, torch_dtype=torch.float16, use_safetensors=True, variant="fp16"
30
  )
 
 
 
 
 
 
 
 
31
  return pipe_t2i
32
 
33
- def load_i2i():
34
  global pipe_i2i
 
35
  if pipe_i2i is None:
36
- from diffusers import StableDiffusionXLImg2ImgPipeline
37
  pipe_i2i = StableDiffusionXLImg2ImgPipeline.from_pretrained(
38
- IMG2IMG_MODEL, torch_dtype=torch.float16, use_safetensors=True, variant="fp16"
39
  )
 
 
 
 
 
 
 
40
  return pipe_i2i
41
 
42
- def load_video(use_lora=True):
43
  global pipe_video
 
44
  if pipe_video is None:
45
- from diffusers import LTXPipeline
46
- pipe_video = LTXPipeline.from_pretrained(
47
- LTX_MODEL, torch_dtype=torch.bfloat16
48
- )
49
- if use_lora:
50
- try:
51
- pipe_video.load_lora_weights(LTX_LORA)
52
- print("[OK] LoRA NSFW cargado.")
53
- except Exception as e:
54
- print(f"[WARN] LoRA no cargado: {e}")
55
  return pipe_video
56
 
57
  # ─── FUNCIONES ─────────────────────────────────────────────────────────────────
58
  @spaces.GPU(duration=120)
59
- def text2img(prompt, neg, steps, cfg, w, h, seed):
60
- pipe = load_t2i().to("cuda")
61
  gen = torch.Generator("cuda").manual_seed(int(seed))
62
- img = pipe(prompt=prompt, negative_prompt=neg,
63
- num_inference_steps=int(steps), guidance_scale=cfg,
64
- width=int(w), height=int(h), generator=gen).images[0]
65
  pipe.to("cpu"); torch.cuda.empty_cache()
66
  return img
67
 
68
  @spaces.GPU(duration=120)
69
- def img2img(prompt, neg, init_image, strength, steps, cfg, seed):
70
- if init_image is None:
71
- return None
72
- pipe = load_i2i().to("cuda")
73
  gen = torch.Generator("cuda").manual_seed(int(seed))
74
  img = Image.fromarray(init_image).convert("RGB").resize((1024, 1024))
75
- result = pipe(prompt=prompt, negative_prompt=neg, image=img,
76
- strength=strength, num_inference_steps=int(steps),
77
- guidance_scale=cfg, generator=gen).images[0]
78
  pipe.to("cpu"); torch.cuda.empty_cache()
79
- return result
80
 
81
  @spaces.GPU(duration=200)
82
- def img2video(prompt, neg, init_image, num_frames, fps, steps, lora_scale, seed):
83
  from diffusers.utils import export_to_video
84
- pipe = load_video(use_lora=True).to("cuda")
85
  gen = torch.Generator("cuda").manual_seed(int(seed))
86
-
87
- kwargs = dict(
88
- prompt=prompt, negative_prompt=neg,
89
- num_frames=int(num_frames), num_inference_steps=int(steps),
90
- generator=gen,
91
- )
92
- if hasattr(pipe, "image") and init_image is not None:
93
- img = Image.fromarray(init_image).convert("RGB").resize((768, 512))
94
- kwargs["image"] = img
95
  if lora_scale > 0:
96
  kwargs["cross_attention_kwargs"] = {"scale": lora_scale}
97
-
98
- output = pipe(**kwargs)
99
- frames = output.frames[0]
100
-
101
- tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
102
- export_to_video(frames, tmp.name, fps=int(fps))
103
- pipe.to("cpu"); torch.cuda.empty_cache()
104
- return tmp.name
105
-
106
- @spaces.GPU(duration=120)
107
- def text2video(prompt, neg, num_frames, fps, w, h, steps, lora_scale, seed):
108
- from diffusers import LTXPipeline
109
- from diffusers.utils import export_to_video
110
- pipe = load_video(use_lora=True).to("cuda")
111
- gen = torch.Generator("cuda").manual_seed(int(seed))
112
-
113
- kwargs = dict(
114
- prompt=prompt, negative_prompt=neg,
115
- num_frames=int(num_frames), width=int(w), height=int(h),
116
- num_inference_steps=int(steps), generator=gen,
117
- )
118
- if lora_scale > 0:
119
- kwargs["cross_attention_kwargs"] = {"scale": lora_scale}
120
-
121
  output = pipe(**kwargs)
122
- frames = output.frames[0]
123
  tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
124
- export_to_video(frames, tmp.name, fps=int(fps))
125
  pipe.to("cpu"); torch.cuda.empty_cache()
126
  return tmp.name
127
 
128
  # ─── UI ────────────────────────────────────────────────────────────────────────
129
- THEME = gr.themes.Base(
130
- primary_hue="violet", secondary_hue="purple", neutral_hue="slate"
131
- ).set(
132
- body_background_fill="#0f0f1a",
133
- block_background_fill="#1a1a2e",
134
- block_border_color="#7c3aed",
135
- input_background_fill="#16213e",
136
- button_primary_background_fill="linear-gradient(135deg, #7c3aed, #db2777)",
137
- button_primary_text_color="white",
138
  )
139
 
140
- CSS = """
141
- h1 { text-align:center; color:#c084fc; font-size:2rem; margin-bottom:4px; }
142
- .subtitle { text-align:center; color:#94a3b8; margin-bottom:1rem; }
143
- .tab-nav button { font-weight:600; }
144
- """
145
-
146
- with gr.Blocks(theme=THEME, css=CSS, title="Studio Privado NSFW") as demo:
147
- gr.HTML("<h1>πŸ”₯ Studio Privado</h1>")
148
- gr.HTML('<p class="subtitle">Generador multimedia sin censura Β· Tus creaciones son privadas y solo las ves vos</p>')
149
-
150
  with gr.Tabs():
151
- # ── TEXT β†’ IMAGE ──────────────────────────────────────────────────────
152
- with gr.Tab("πŸ–Ό Text β†’ Image"):
153
- with gr.Row():
154
- with gr.Column():
155
- t2i_prompt = gr.Textbox(label="Prompt", lines=3,
156
- placeholder="A beautiful woman, photorealistic, 8k, detailed...")
157
- t2i_neg = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT, lines=2)
158
- with gr.Row():
159
- t2i_steps = gr.Slider(10, 60, 30, step=1, label="Pasos")
160
- t2i_cfg = gr.Slider(1, 20, 7.5, step=0.5, label="CFG")
161
- with gr.Row():
162
- t2i_w = gr.Slider(512, 1280, 1024, step=64, label="Ancho")
163
- t2i_h = gr.Slider(512, 1280, 1024, step=64, label="Alto")
164
- t2i_seed = gr.Number(42, label="Seed")
165
- t2i_btn = gr.Button("πŸš€ Generar Imagen", variant="primary", size="lg")
166
- with gr.Column():
167
- t2i_out = gr.Image(label="Resultado", type="pil", height=500)
168
- t2i_btn.click(text2img,
169
- [t2i_prompt, t2i_neg, t2i_steps, t2i_cfg, t2i_w, t2i_h, t2i_seed],
170
- t2i_out)
171
-
172
- # ── IMAGE β†’ IMAGE ─────────────────────────────────────────────────────
173
- with gr.Tab("πŸ”„ Image β†’ Image"):
174
  with gr.Row():
175
  with gr.Column():
176
- i2i_input = gr.Image(label="Imagen Base", type="numpy")
177
- i2i_prompt = gr.Textbox(label="Prompt", lines=3,
178
- placeholder="Modify the image to...")
179
- i2i_neg = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT, lines=2)
180
  with gr.Row():
181
- i2i_str = gr.Slider(0.1, 1.0, 0.6, step=0.05, label="Intensidad")
182
- i2i_steps = gr.Slider(10, 60, 30, step=1, label="Pasos")
183
  with gr.Row():
184
- i2i_cfg = gr.Slider(1, 20, 7.5, step=0.5, label="CFG")
185
- i2i_seed = gr.Number(42, label="Seed")
186
- i2i_btn = gr.Button("πŸš€ Transformar Imagen", variant="primary", size="lg")
187
- with gr.Column():
188
- i2i_out = gr.Image(label="Resultado", type="pil", height=500)
189
- i2i_btn.click(img2img,
190
- [i2i_prompt, i2i_neg, i2i_input, i2i_str, i2i_steps, i2i_cfg, i2i_seed],
191
- i2i_out)
192
 
193
- # ── TEXT β†’ VIDEO (LTX) ────────────────────────────────────────────────
194
- with gr.Tab("🎬 Text β†’ Video (LTX)"):
195
- gr.Markdown("*Usa LTX-Video con LoRA NSFW. Genera entre 25 y 121 frames.*")
196
  with gr.Row():
197
  with gr.Column():
198
- t2v_prompt = gr.Textbox(label="Prompt", lines=3,
199
- placeholder="A woman walking in slow motion, cinematic, 4k...")
200
- t2v_neg = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT, lines=2)
201
- with gr.Row():
202
- t2v_frames = gr.Slider(25, 121, 49, step=8, label="Frames")
203
- t2v_fps = gr.Slider(8, 30, 24, step=1, label="FPS")
204
- with gr.Row():
205
- t2v_w = gr.Slider(256, 768, 512, step=64, label="Ancho")
206
- t2v_h = gr.Slider(256, 768, 512, step=64, label="Alto")
207
- with gr.Row():
208
- t2v_steps = gr.Slider(10, 50, 30, step=1, label="Pasos")
209
- t2v_lora = gr.Slider(0.0, 1.5, 0.8, step=0.05, label="LoRA Scale")
210
- t2v_seed = gr.Number(42, label="Seed")
211
- t2v_btn = gr.Button("🎬 Generar Video", variant="primary", size="lg")
212
- with gr.Column():
213
- t2v_out = gr.Video(label="Video Generado")
214
- t2v_btn.click(text2video,
215
- [t2v_prompt, t2v_neg, t2v_frames, t2v_fps, t2v_w, t2v_h, t2v_steps, t2v_lora, t2v_seed],
216
- t2v_out)
217
-
218
- # ── IMAGE β†’ VIDEO (LTX) ───────────────────────────────────────────────
219
- with gr.Tab("πŸ“Ή Image β†’ Video (LTX)"):
220
- gr.Markdown("*AnimΓ‘ una imagen usando LTX-Video + LoRA NSFW.*")
221
- with gr.Row():
222
- with gr.Column():
223
- i2v_input = gr.Image(label="Imagen Base (se usarΓ‘ como frame inicial)", type="numpy")
224
- i2v_prompt = gr.Textbox(label="Prompt de movimiento", lines=3,
225
- placeholder="The woman slowly turns her head, smooth motion...")
226
- i2v_neg = gr.Textbox(label="Negative Prompt", value=NEG_DEFAULT, lines=2)
227
- with gr.Row():
228
- i2v_frames = gr.Slider(25, 121, 49, step=8, label="Frames")
229
- i2v_fps = gr.Slider(8, 30, 24, step=1, label="FPS")
230
- with gr.Row():
231
- i2v_steps = gr.Slider(10, 50, 30, step=1, label="Pasos")
232
- i2v_lora = gr.Slider(0.0, 1.5, 0.8, step=0.05, label="LoRA Scale")
233
- i2v_seed = gr.Number(42, label="Seed")
234
- i2v_btn = gr.Button("πŸ“Ή Animar Imagen", variant="primary", size="lg")
235
- with gr.Column():
236
- i2v_out = gr.Video(label="Video Generado")
237
- i2v_btn.click(img2video,
238
- [i2v_prompt, i2v_neg, i2v_input, i2v_frames, i2v_fps, i2v_steps, i2v_lora, i2v_seed],
239
- i2v_out)
240
 
241
  demo.launch()
 
4
  import numpy as np
5
  from PIL import Image
6
  import tempfile, os
7
+ from huggingface_hub import hf_hub_download
8
 
9
+ # ─── CONFIGURACIΓ“N DE MODELOS ──────────────────────────────────────────────────
10
+ # Usamos CyberRealistic Pony por su alto realismo en humanos
11
+ BASE_MODEL = "cyberdelia/CyberRealisticPony"
12
+ LTX_MODEL = "Lightricks/LTX-Video"
13
+ DEFAULT_LORA = "John6666/nsfw-master-flux-lora-merged" # Sugerido para imagenes
14
+ LTX_NSFW_LORA = "Lora-Daddy/Ltx2.3-real-nudity-early-alpha-30k-steps"
15
 
16
+ pipe_t2i = None
17
+ pipe_i2i = None
18
  pipe_video = None
19
 
20
+ NEG_DEFAULT = "censored, blurry, low quality, bad anatomy, deformed, ugly, watermark, text, signature"
 
 
 
21
 
22
  # ─── LOADERS ───────────────────────────────────────────────────────────────────
23
+ def load_t2i(lora_id=None, lora_scale=1.0):
24
  global pipe_t2i
25
+ from diffusers import StableDiffusionXLPipeline
26
  if pipe_t2i is None:
 
27
  pipe_t2i = StableDiffusionXLPipeline.from_pretrained(
28
+ BASE_MODEL, torch_dtype=torch.float16, use_safetensors=True, variant="fp16"
29
  )
30
+
31
+ if lora_id:
32
+ try:
33
+ pipe_t2i.unload_lora_weights()
34
+ pipe_t2i.load_lora_weights(lora_id)
35
+ pipe_t2i.fuse_lora(lora_scale=lora_scale)
36
+ except Exception as e:
37
+ print(f"Error cargando LoRA: {e}")
38
  return pipe_t2i
39
 
40
+ def load_i2i(lora_id=None, lora_scale=1.0):
41
  global pipe_i2i
42
+ from diffusers import StableDiffusionXLImg2ImgPipeline
43
  if pipe_i2i is None:
 
44
  pipe_i2i = StableDiffusionXLImg2ImgPipeline.from_pretrained(
45
+ BASE_MODEL, torch_dtype=torch.float16, use_safetensors=True, variant="fp16"
46
  )
47
+ if lora_id:
48
+ try:
49
+ pipe_i2i.unload_lora_weights()
50
+ pipe_i2i.load_lora_weights(lora_id)
51
+ pipe_i2i.fuse_lora(lora_scale=lora_scale)
52
+ except Exception as e:
53
+ print(f"Error cargando LoRA: {e}")
54
  return pipe_i2i
55
 
56
+ def load_video():
57
  global pipe_video
58
+ from diffusers import LTXPipeline
59
  if pipe_video is None:
60
+ pipe_video = LTXPipeline.from_pretrained(LTX_MODEL, torch_dtype=torch.bfloat16)
61
+ try:
62
+ pipe_video.load_lora_weights(LTX_NSFW_LORA)
63
+ except: pass
 
 
 
 
 
 
64
  return pipe_video
65
 
66
  # ─── FUNCIONES ─────────────────────────────────────────────────────────────────
67
  @spaces.GPU(duration=120)
68
+ def generate_t2i(prompt, neg, lora_id, lora_scale, steps, cfg, w, h, seed):
69
+ pipe = load_t2i(lora_id if lora_id else None, lora_scale).to("cuda")
70
  gen = torch.Generator("cuda").manual_seed(int(seed))
71
+ img = pipe(prompt=prompt, negative_prompt=neg, num_inference_steps=int(steps),
72
+ guidance_scale=cfg, width=int(w), height=int(h), generator=gen).images[0]
 
73
  pipe.to("cpu"); torch.cuda.empty_cache()
74
  return img
75
 
76
  @spaces.GPU(duration=120)
77
+ def generate_i2i(prompt, neg, init_image, strength, lora_id, lora_scale, steps, cfg, seed):
78
+ if init_image is None: return None
79
+ pipe = load_i2i(lora_id if lora_id else None, lora_scale).to("cuda")
 
80
  gen = torch.Generator("cuda").manual_seed(int(seed))
81
  img = Image.fromarray(init_image).convert("RGB").resize((1024, 1024))
82
+ res = pipe(prompt=prompt, negative_prompt=neg, image=img, strength=strength,
83
+ num_inference_steps=int(steps), guidance_scale=cfg, generator=gen).images[0]
 
84
  pipe.to("cpu"); torch.cuda.empty_cache()
85
+ return res
86
 
87
  @spaces.GPU(duration=200)
88
+ def generate_video(prompt, neg, init_image, num_frames, fps, steps, lora_scale, seed):
89
  from diffusers.utils import export_to_video
90
+ pipe = load_video().to("cuda")
91
  gen = torch.Generator("cuda").manual_seed(int(seed))
92
+
93
+ kwargs = {"prompt": prompt, "negative_prompt": neg, "num_frames": int(num_frames),
94
+ "num_inference_steps": int(steps), "generator": gen}
95
+
96
+ if init_image is not None:
97
+ kwargs["image"] = Image.fromarray(init_image).convert("RGB").resize((768, 512))
98
+
 
 
99
  if lora_scale > 0:
100
  kwargs["cross_attention_kwargs"] = {"scale": lora_scale}
101
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  output = pipe(**kwargs)
 
103
  tmp = tempfile.NamedTemporaryFile(suffix=".mp4", delete=False)
104
+ export_to_video(output.frames[0], tmp.name, fps=int(fps))
105
  pipe.to("cpu"); torch.cuda.empty_cache()
106
  return tmp.name
107
 
108
  # ─── UI ────────────────────────────────────────────────────────────────────────
109
+ THEME = gr.themes.Soft(primary_hue="violet", neutral_hue="slate").set(
110
+ body_background_fill="#0b0f19", block_background_fill="#161b22",
111
+ button_primary_background_fill="linear-gradient(90deg, #7c3aed, #db2777)"
 
 
 
 
 
 
112
  )
113
 
114
+ with gr.Blocks(theme=THEME, title="Studio Privado V2") as demo:
115
+ gr.HTML("<h1 style='text-align:center; color:#db2777;'>πŸ”₯ Studio Privado V2 - Ultra Realismo</h1>")
116
+
 
 
 
 
 
 
 
117
  with gr.Tabs():
118
+ with gr.Tab("πŸ–Ό Imagen (Text2Img)"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  with gr.Row():
120
  with gr.Column():
121
+ t2i_p = gr.Textbox(label="Prompt", lines=3, placeholder="A photorealistic woman...")
122
+ t2i_n = gr.Textbox(label="Negativo", value=NEG_DEFAULT)
 
 
123
  with gr.Row():
124
+ t2i_lora = gr.Textbox(label="Custom LoRA ID", placeholder="ej: John6666/nsfw-master-flux-lora-merged")
125
+ t2i_ls = gr.Slider(0, 1.5, 0.8, label="Fuerza LoRA")
126
  with gr.Row():
127
+ t2i_w = gr.Slider(512, 1280, 1024, step=64, label="Ancho")
128
+ t2i_h = gr.Slider(512, 1280, 1024, step=64, label="Alto")
129
+ t2i_btn = gr.Button("Generar Imagen", variant="primary")
130
+ t2i_out = gr.Image(label="Resultado")
131
+ t2i_btn.click(generate_t2i, [t2i_p, t2i_n, t2i_lora, t2i_ls, gr.Number(30), gr.Number(7.5), t2i_w, t2i_h, gr.Number(42)], t2i_out)
 
 
 
132
 
133
+ with gr.Tab("🎬 Video (LTX-Video)"):
 
 
134
  with gr.Row():
135
  with gr.Column():
136
+ v_p = gr.Textbox(label="Prompt de Video", lines=3)
137
+ v_img = gr.Image(label="Imagen Base (opcional)", type="numpy")
138
+ v_ls = gr.Slider(0, 1.5, 0.8, label="Fuerza LoRA NSFW")
139
+ v_btn = gr.Button("Generar Video", variant="primary")
140
+ v_out = gr.Video(label="Resultado")
141
+ v_btn.click(generate_video, [v_p, gr.Textbox(value=NEG_DEFAULT), v_img, gr.Number(49), gr.Number(24), gr.Number(30), v_ls, gr.Number(42)], v_out)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  demo.launch()