cobramv12 commited on
Commit
fe964d2
Β·
verified Β·
1 Parent(s): c62b324

Update app.py - full NSFW studio

Browse files
Files changed (1) hide show
  1. app.py +231 -65
app.py CHANGED
@@ -1,75 +1,241 @@
1
  import spaces
2
  import gradio as gr
3
  import torch
4
- from diffusers import DiffusionPipeline
5
- from huggingface_hub import hf_hub_download
6
-
7
- # Cargamos el modelo base - usaremos SDXL como base
8
- # PodΓ©s cambiar esto por cualquier modelo de HuggingFace
9
- MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
10
- pipe = None
11
-
12
- def load_pipeline():
13
- global pipe
14
- if pipe is None:
15
- pipe = DiffusionPipeline.from_pretrained(
16
- MODEL_ID,
17
- torch_dtype=torch.float16,
18
- use_safetensors=True,
19
- variant="fp16"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  )
21
- return pipe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  @spaces.GPU(duration=120)
24
- def generate(prompt, negative_prompt, steps, cfg_scale, width, height, seed):
25
- global pipe
26
- pipe = load_pipeline()
27
- pipe = pipe.to("cuda")
28
-
29
- generator = torch.Generator("cuda").manual_seed(int(seed))
30
-
31
- images = pipe(
32
- prompt=prompt,
33
- negative_prompt=negative_prompt,
34
- num_inference_steps=int(steps),
35
- guidance_scale=cfg_scale,
36
- width=int(width),
37
- height=int(height),
38
- generator=generator
39
- ).images
40
-
41
- pipe = pipe.to("cpu") # Liberar VRAM despues de generar
42
- torch.cuda.empty_cache()
43
-
44
- return images[0]
45
-
46
- with gr.Blocks(title="Studio Privado", theme=gr.themes.Soft()) as demo:
47
- gr.Markdown("## 🎨 Studio Privado - Generador de ImÑgenes")
48
- gr.Markdown("*Tus creaciones son privadas. Nadie mΓ‘s puede verlas.*")
49
-
50
- with gr.Row():
51
- with gr.Column(scale=1):
52
- prompt = gr.Textbox(label="Prompt", placeholder="Describe lo que querΓ©s generar...", lines=3)
53
- negative_prompt = gr.Textbox(label="Negative Prompt", value="blurry, low quality, bad anatomy", lines=2)
54
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  with gr.Row():
56
- steps = gr.Slider(10, 50, value=30, step=1, label="Pasos")
57
- cfg = gr.Slider(1, 20, value=7.5, step=0.5, label="CFG Scale")
58
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  with gr.Row():
60
- width = gr.Slider(512, 1024, value=1024, step=64, label="Ancho")
61
- height = gr.Slider(512, 1024, value=1024, step=64, label="Alto")
62
-
63
- seed = gr.Number(value=42, label="Seed (-1 para random)")
64
- btn = gr.Button("πŸš€ Generar", variant="primary", size="lg")
65
-
66
- with gr.Column(scale=1):
67
- output = gr.Image(label="Resultado", type="pil")
68
-
69
- btn.click(
70
- fn=generate,
71
- inputs=[prompt, negative_prompt, steps, cfg, width, height, seed],
72
- outputs=output
73
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  demo.launch()
 
1
  import spaces
2
  import gradio as gr
3
  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()