Ntdeseb commited on
Commit
2f81f18
·
1 Parent(s): 63df3b5

Agregados todos los modelos exitosos del Space test - FLUX, Turbo, Lightning, optimizaciones H200 completas

Browse files
Files changed (1) hide show
  1. app.py +790 -84
app.py CHANGED
@@ -61,19 +61,75 @@ else:
61
  MODELS = {
62
  "text": {
63
  "microsoft/DialoGPT-medium": "Chat conversacional",
 
 
64
  "gpt2": "Generación de texto",
65
- "distilgpt2": "GPT-2 optimizado"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  },
67
  "image": {
68
- "CompVis/stable-diffusion-v1-4": "Stable Diffusion v1.4 (Libre)",
69
- "stabilityai/stable-diffusion-2-1": "Stable Diffusion 2.1",
 
 
 
 
70
  "stabilityai/stable-diffusion-xl-base-1.0": "SDXL Base",
 
 
 
 
 
71
  "prompthero/openjourney": "Midjourney Style",
72
- "hakurei/waifu-diffusion": "Waifu Diffusion"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  },
74
  "video": {
75
  "damo-vilab/text-to-video-ms-1.7b": "Text-to-Video MS 1.7B (Libre)",
76
- "cerspense/zeroscope_v2_576w": "Zeroscope v2 576w (Libre)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  }
78
  }
79
 
@@ -118,43 +174,392 @@ def load_text_model(model_name):
118
  def load_image_model(model_name):
119
  """Cargar modelo de imagen optimizado para H200"""
120
  if model_name not in model_cache:
121
- print(f"Cargando modelo de imagen: {model_name}")
122
 
123
  try:
124
- pipe = StableDiffusionPipeline.from_pretrained(
125
- model_name,
126
- torch_dtype=torch_dtype,
127
- safety_checker=None
128
- )
 
 
 
 
 
 
 
 
 
 
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  pipe = pipe.to(device)
131
 
132
- # Optimizaciones para H200
133
  if torch.cuda.is_available():
134
- pipe.enable_attention_slicing()
135
- pipe.enable_vae_slicing()
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  if hasattr(pipe, 'enable_xformers_memory_efficient_attention'):
138
- try:
139
- pipe.enable_xformers_memory_efficient_attention()
140
- except:
141
- pass
 
 
 
 
 
 
 
 
142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  model_cache[model_name] = pipe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
  except Exception as e:
146
- print(f"Error cargando modelo {model_name}: {e}")
147
- # Fallback
148
- pipe = StableDiffusionPipeline.from_pretrained(
149
- "CompVis/stable-diffusion-v1-4",
150
- torch_dtype=torch_dtype,
151
- safety_checker=None
152
- )
153
- pipe = pipe.to(device)
154
- model_cache[model_name] = pipe
 
 
 
 
 
 
 
 
155
 
156
  return model_cache[model_name]
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  def generate_text(prompt, model_name, max_length=100):
159
  """Generar texto con el modelo seleccionado"""
160
  try:
@@ -188,28 +593,172 @@ def generate_text(prompt, model_name, max_length=100):
188
  def generate_image(prompt, model_name, negative_prompt="", seed=0, width=1024, height=1024, guidance_scale=7.5, num_inference_steps=20):
189
  """Generar imagen optimizada para H200"""
190
  try:
191
- print(f"Generando imagen: {prompt}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
 
 
 
 
 
 
 
 
193
  pipe = load_image_model(model_name)
194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  generator = torch.Generator(device=device).manual_seed(seed)
196
 
197
- result = pipe(
198
- prompt=prompt,
199
- negative_prompt=negative_prompt,
200
- height=height,
201
- width=width,
202
- guidance_scale=guidance_scale,
203
- num_inference_steps=num_inference_steps,
204
- generator=generator
205
- )
206
-
207
- image = result.images[0]
208
- print(" Imagen generada exitosamente")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  return image
210
 
211
  except Exception as e:
212
- print(f"Error generando imagen: {e}")
 
 
 
213
  error_image = Image.new('RGB', (512, 512), color='red')
214
  return error_image
215
 
@@ -254,10 +803,45 @@ def chat_with_model(message, history, model_name):
254
  history.append({"role": "assistant", "content": error_msg})
255
  return history
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  # Interfaz de Gradio
258
  with gr.Blocks(title="Modelos Libres de IA", theme=gr.themes.Soft()) as demo:
259
  gr.Markdown("# 🤖 Modelos Libres de IA")
260
- gr.Markdown("### Genera texto e imágenes sin límites de cuota")
261
 
262
  with gr.Tabs():
263
  # Tab de Generación de Texto
@@ -301,7 +885,7 @@ with gr.Blocks(title="Modelos Libres de IA", theme=gr.themes.Soft()) as demo:
301
  with gr.Row():
302
  with gr.Column():
303
  chat_model = gr.Dropdown(
304
- choices=list(MODELS["text"].keys()),
305
  value="microsoft/DialoGPT-medium",
306
  label="Modelo de Chat"
307
  )
@@ -331,86 +915,166 @@ with gr.Blocks(title="Modelos Libres de IA", theme=gr.themes.Soft()) as demo:
331
  outputs=[chatbot]
332
  )
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  # Tab de Generación de Imágenes
335
  with gr.TabItem("🎨 Generación de Imágenes"):
336
  with gr.Row():
337
  with gr.Column():
 
338
  image_model = gr.Dropdown(
339
  choices=list(MODELS["image"].keys()),
340
  value="CompVis/stable-diffusion-v1-4",
341
- label="Modelo"
 
342
  )
343
 
 
344
  image_prompt = gr.Textbox(
345
  label="Prompt",
346
  placeholder="Describe la imagen que quieres generar...",
347
  lines=3
348
  )
349
 
 
350
  negative_prompt = gr.Textbox(
351
  label="Negative prompt",
352
  placeholder="Enter a negative prompt (optional)",
353
  lines=2
354
  )
355
 
356
- with gr.Row():
357
- seed = gr.Slider(
358
- minimum=0,
359
- maximum=2147483647,
360
- value=324354329,
361
- step=1,
362
- label="Seed"
363
- )
364
- guidance_scale = gr.Slider(
365
- minimum=0,
366
- maximum=20,
367
- value=7.5,
368
- step=0.1,
369
- label="Guidance scale"
370
- )
371
-
372
- with gr.Row():
373
- width = gr.Slider(
374
- minimum=256,
375
- maximum=1024,
376
- value=1024,
377
- step=64,
378
- label="Width"
379
- )
380
- height = gr.Slider(
381
- minimum=256,
382
- maximum=1024,
383
- value=1024,
384
- step=64,
385
- label="Height"
386
- )
387
-
388
- num_inference_steps = gr.Slider(
389
- minimum=1,
390
- maximum=100,
391
- value=20,
392
- step=1,
393
- label="Number of inference steps"
394
- )
 
 
 
 
 
 
 
 
 
 
395
 
 
396
  image_btn = gr.Button("Generar Imagen", variant="primary")
397
 
398
  with gr.Column():
 
 
 
 
 
 
 
 
 
399
  examples = gr.Examples(
400
  examples=[
401
  ["Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"],
402
  ["An astronaut riding a green horse"],
403
  ["A delicious ceviche cheesecake slice"],
404
- ["Futuristic AI assistant in a glowing galaxy, neon lights, sci-fi style, cinematic"]
 
 
 
 
405
  ],
406
  inputs=image_prompt
407
  )
408
 
 
409
  image_output = gr.Image(
410
  label="Imagen Generada",
411
  type="pil"
412
  )
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  image_btn.click(
415
  generate_image,
416
  inputs=[
@@ -425,6 +1089,48 @@ with gr.Blocks(title="Modelos Libres de IA", theme=gr.themes.Soft()) as demo:
425
  ],
426
  outputs=image_output
427
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
 
429
  # Configuración para Hugging Face Spaces
430
  if __name__ == "__main__":
 
61
  MODELS = {
62
  "text": {
63
  "microsoft/DialoGPT-medium": "Chat conversacional",
64
+ "microsoft/DialoGPT-large": "Chat conversacional avanzado",
65
+ "microsoft/DialoGPT-small": "Chat conversacional rápido",
66
  "gpt2": "Generación de texto",
67
+ "gpt2-medium": "GPT-2 mediano",
68
+ "gpt2-large": "GPT-2 grande",
69
+ "distilgpt2": "GPT-2 optimizado",
70
+ "EleutherAI/gpt-neo-125M": "GPT-Neo pequeño",
71
+ "EleutherAI/gpt-neo-1.3B": "GPT-Neo mediano",
72
+ "facebook/opt-125m": "OPT pequeño",
73
+ "facebook/opt-350m": "OPT mediano",
74
+ "bigscience/bloom-560m": "BLOOM multilingüe",
75
+ "bigscience/bloom-1b1": "BLOOM grande",
76
+ "Helsinki-NLP/opus-mt-es-en": "Traductor español-inglés",
77
+ "Helsinki-NLP/opus-mt-en-es": "Traductor inglés-español",
78
+ # ✅ Nuevos modelos de texto
79
+ "mistralai/Voxtral-Mini-3B-2507": "Voxtral Mini 3B - Multimodal",
80
+ "tiiuae/falcon-7b-instruct": "Falcon 7B Instruct",
81
+ "google/flan-t5-base": "Flan-T5 Base - Tareas múltiples"
82
  },
83
  "image": {
84
+ # Modelos Turbo (rápidos) - Optimizados para H200
85
+ "stabilityai/sdxl-turbo": " SDXL Turbo",
86
+ "stabilityai/sd-turbo": "⚡ SD Turbo",
87
+ "ByteDance/SDXL-Lightning": "⚡ SDXL Lightning",
88
+
89
+ # 🎨 Modelos base de alta calidad
90
  "stabilityai/stable-diffusion-xl-base-1.0": "SDXL Base",
91
+ "stabilityai/stable-diffusion-2-1": "Stable Diffusion 2.1",
92
+ "CompVis/stable-diffusion-v1-4": "Stable Diffusion v1.4 (Libre)",
93
+ "runwayml/stable-diffusion-v1-5": "Stable Diffusion v1.5",
94
+
95
+ # 🎭 Modelos de estilo específico
96
  "prompthero/openjourney": "Midjourney Style",
97
+ "prompthero/openjourney-v4": "OpenJourney v4",
98
+ "WarriorMama777/OrangeMixs": "Orange Mixs",
99
+ "hakurei/waifu-diffusion": "Waifu Diffusion",
100
+ "SG161222/Realistic_Vision_V5.1_noVAE": "Realistic Vision",
101
+ "Linaqruf/anything-v3.0": "Anything v3",
102
+ "XpucT/deliberate-v2": "Deliberate v2",
103
+ "dreamlike-art/dreamlike-diffusion-1.0": "Dreamlike Diffusion",
104
+ "KBlueLeaf/kohaku-v2.1": "Kohaku V2.1",
105
+
106
+ # 🔐 Modelos FLUX (requieren HF_TOKEN)
107
+ "black-forest-labs/FLUX.1-dev": "FLUX.1 Dev (Requiere acceso)",
108
+ "black-forest-labs/FLUX.1-schnell": "FLUX.1 Schnell (Requiere acceso)",
109
+
110
+ # 📦 Modelos adicionales
111
+ "CompVis/ldm-text2im-large-256": "Latent Diffusion Model 256"
112
  },
113
  "video": {
114
  "damo-vilab/text-to-video-ms-1.7b": "Text-to-Video MS 1.7B (Libre)",
115
+ "ali-vilab/text-to-video-ms-1.7b": "Text-to-Video MS 1.7B Alt",
116
+ "cerspense/zeroscope_v2_576w": "Zeroscope v2 576w (Libre)",
117
+ "cerspense/zeroscope_v2_XL": "Zeroscope v2 XL (Libre)",
118
+ "ByteDance/AnimateDiff-Lightning": "AnimateDiff Lightning (Libre)",
119
+ "THUDM/CogVideoX-5b": "CogVideoX 5B (Libre)",
120
+ "rain1011/pyramid-flow-sd3": "Pyramid Flow SD3 (Libre)",
121
+ # ✅ Nuevos modelos de video
122
+ "ali-vilab/modelscope-damo-text-to-video-synthesis": "ModelScope Text-to-Video"
123
+ },
124
+ "chat": {
125
+ "microsoft/DialoGPT-medium": "Chat conversacional",
126
+ "microsoft/DialoGPT-large": "Chat conversacional avanzado",
127
+ "microsoft/DialoGPT-small": "Chat conversacional rápido",
128
+ "facebook/opt-350m": "OPT conversacional",
129
+ "bigscience/bloom-560m": "BLOOM multilingüe",
130
+ # ✅ Nuevos modelos de chat
131
+ "mistralai/Voxtral-Mini-3B-2507": "Voxtral Mini 3B - Multimodal",
132
+ "tiiuae/falcon-7b-instruct": "Falcon 7B Instruct"
133
  }
134
  }
135
 
 
174
  def load_image_model(model_name):
175
  """Cargar modelo de imagen optimizado para H200"""
176
  if model_name not in model_cache:
177
+ print(f"\n🔄 Iniciando carga del modelo: {model_name}")
178
 
179
  try:
180
+ start_time = time.time()
181
+
182
+ # Determinar si usar variant fp16 basado en el modelo
183
+ use_fp16_variant = False
184
+ if torch.cuda.is_available():
185
+ # Solo usar fp16 variant para modelos que lo soportan
186
+ fp16_supported_models = [
187
+ "stabilityai/sdxl-turbo",
188
+ "stabilityai/sd-turbo",
189
+ "stabilityai/stable-diffusion-xl-base-1.0",
190
+ "runwayml/stable-diffusion-v1-5",
191
+ "CompVis/stable-diffusion-v1-4"
192
+ ]
193
+ use_fp16_variant = any(model in model_name for model in fp16_supported_models)
194
+ print(f"🔧 FP16 variant: {'✅ Habilitado' if use_fp16_variant else '❌ Deshabilitado'} para {model_name}")
195
 
196
+ # Configuración especial para FLUX
197
+ if "flux" in model_name.lower() or "black-forest" in model_name.lower():
198
+ if not HF_TOKEN:
199
+ print("❌ No hay acceso a modelos gated. Configura HF_TOKEN en el Space.")
200
+ raise Exception("Acceso denegado a modelos FLUX. Configura HF_TOKEN en las variables de entorno del Space.")
201
+
202
+ try:
203
+ from diffusers import FluxPipeline
204
+ print("🚀 Cargando FLUX Pipeline...")
205
+ print(f"🔧 Modelo: {model_name}")
206
+ print(f"🔑 Usando token de autenticación: {'Sí' if HF_TOKEN else 'No'}")
207
+
208
+ # Para modelos FLUX, no usar variant fp16
209
+ pipe = FluxPipeline.from_pretrained(
210
+ model_name,
211
+ torch_dtype=torch_dtype,
212
+ use_auth_token=HF_TOKEN,
213
+ variant="fp16" if use_fp16_variant else None
214
+ )
215
+
216
+ print("✅ FLUX Pipeline cargado exitosamente")
217
+
218
+ except Exception as e:
219
+ print(f"❌ Error cargando FLUX: {e}")
220
+ print(f"🔍 Tipo de error: {type(e).__name__}")
221
+
222
+ # Si es un error de autenticación, dar instrucciones específicas
223
+ if "401" in str(e) or "unauthorized" in str(e).lower():
224
+ print("🔐 Error de autenticación. Asegúrate de:")
225
+ print(" 1. Tener acceso al modelo FLUX en Hugging Face")
226
+ print(" 2. Configurar HF_TOKEN en las variables de entorno del Space")
227
+ print(" 3. Que el token tenga permisos para acceder a modelos gated")
228
+
229
+ # Fallback a Stable Diffusion
230
+ print("🔄 Fallback a Stable Diffusion...")
231
+ pipe = StableDiffusionPipeline.from_pretrained(
232
+ "CompVis/stable-diffusion-v1-4",
233
+ torch_dtype=torch_dtype,
234
+ safety_checker=None
235
+ )
236
+
237
+ # Configuración especial para SD 2.1 (problemático)
238
+ elif "stable-diffusion-2-1" in model_name:
239
+ try:
240
+ pipe = StableDiffusionPipeline.from_pretrained(
241
+ model_name,
242
+ torch_dtype=torch_dtype,
243
+ safety_checker=None,
244
+ requires_safety_checker=False,
245
+ variant="fp16" if use_fp16_variant else None
246
+ )
247
+ except Exception as e:
248
+ print(f"Error cargando SD 2.1: {e}")
249
+ # Fallback a SD 1.4
250
+ pipe = StableDiffusionPipeline.from_pretrained(
251
+ "CompVis/stable-diffusion-v1-4",
252
+ torch_dtype=torch_dtype,
253
+ safety_checker=None
254
+ )
255
+
256
+ # Configuración especial para LDM
257
+ elif "ldm-text2im" in model_name:
258
+ try:
259
+ from diffusers import DiffusionPipeline
260
+ pipe = DiffusionPipeline.from_pretrained(
261
+ model_name,
262
+ torch_dtype=torch_dtype,
263
+ safety_checker=None
264
+ )
265
+ except Exception as e:
266
+ print(f"Error cargando LDM: {e}")
267
+ # Fallback a SD 1.4
268
+ pipe = StableDiffusionPipeline.from_pretrained(
269
+ "CompVis/stable-diffusion-v1-4",
270
+ torch_dtype=torch_dtype,
271
+ safety_checker=None
272
+ )
273
+
274
+ # Configuración estándar para otros modelos
275
+ else:
276
+ try:
277
+ pipe = StableDiffusionPipeline.from_pretrained(
278
+ model_name,
279
+ torch_dtype=torch_dtype,
280
+ safety_checker=None,
281
+ variant="fp16" if use_fp16_variant else None
282
+ )
283
+ except Exception as e:
284
+ print(f"Error cargando {model_name}: {e}")
285
+ # Fallback a SD 1.4
286
+ pipe = StableDiffusionPipeline.from_pretrained(
287
+ "CompVis/stable-diffusion-v1-4",
288
+ torch_dtype=torch_dtype,
289
+ safety_checker=None
290
+ )
291
+
292
+ load_time = time.time() - start_time
293
+ print(f"⏱️ Tiempo de carga: {load_time:.2f} segundos")
294
+
295
+ print(f"🚀 Moviendo modelo a dispositivo: {device}")
296
  pipe = pipe.to(device)
297
 
298
+ # Optimizaciones específicas para H200
299
  if torch.cuda.is_available():
300
+ print("🔧 Aplicando optimizaciones para H200...")
 
301
 
302
+ # Habilitar optimizaciones de memoria (más conservadoras)
303
+ if hasattr(pipe, 'enable_attention_slicing'):
304
+ pipe.enable_attention_slicing()
305
+ print("✅ Attention slicing habilitado")
306
+
307
+ # Deshabilitar CPU offload temporalmente (causa problemas con ZeroGPU)
308
+ # if hasattr(pipe, 'enable_model_cpu_offload') and "sdxl" in model_name.lower():
309
+ # pipe.enable_model_cpu_offload()
310
+ # print("✅ CPU offload habilitado (modelo grande)")
311
+
312
+ if hasattr(pipe, 'enable_vae_slicing'):
313
+ pipe.enable_vae_slicing()
314
+ print("✅ VAE slicing habilitado")
315
+
316
+ # XFormers solo si está disponible y el modelo lo soporta
317
  if hasattr(pipe, 'enable_xformers_memory_efficient_attention'):
318
+ # FLUX models tienen problemas con XFormers, deshabilitar
319
+ if "flux" in model_name.lower() or "black-forest" in model_name.lower():
320
+ print("⚠️ XFormers deshabilitado para modelos FLUX (incompatible)")
321
+ else:
322
+ try:
323
+ pipe.enable_xformers_memory_efficient_attention()
324
+ print("✅ XFormers memory efficient attention habilitado")
325
+ except Exception as e:
326
+ print(f"⚠️ XFormers no disponible: {e}")
327
+ print("🔄 Usando atención estándar")
328
+
329
+ print(f"✅ Modelo {model_name} cargado exitosamente")
330
 
331
+ if torch.cuda.is_available():
332
+ memory_used = torch.cuda.memory_allocated() / 1024**3
333
+ memory_reserved = torch.cuda.memory_reserved() / 1024**3
334
+ print(f"💾 Memoria GPU utilizada: {memory_used:.2f} GB")
335
+ print(f"💾 Memoria GPU reservada: {memory_reserved:.2f} GB")
336
+
337
+ # Verificar si la memoria es sospechosamente baja
338
+ if memory_used < 0.1:
339
+ print("⚠️ ADVERTENCIA: Memoria GPU muy baja - posible problema de carga")
340
+ else:
341
+ print("💾 Memoria CPU")
342
+
343
+ # Guardar en cache
344
  model_cache[model_name] = pipe
345
+
346
+ except Exception as e:
347
+ print(f"❌ Error cargando modelo {model_name}: {e}")
348
+ print(f"🔍 Tipo de error: {type(e).__name__}")
349
+
350
+ # Intentar cargar sin variant fp16 si falló
351
+ if "variant" in str(e) and "fp16" in str(e):
352
+ print("🔄 Reintentando sin variant fp16...")
353
+ try:
354
+ pipe = StableDiffusionPipeline.from_pretrained(
355
+ model_name,
356
+ torch_dtype=torch_dtype,
357
+ use_auth_token=HF_TOKEN if HF_TOKEN and ("flux" in model_name.lower() or "black-forest" in model_name.lower()) else None
358
+ )
359
+ pipe = pipe.to(device)
360
+ model_cache[model_name] = pipe
361
+ print(f"✅ Modelo {model_name} cargado exitosamente (sin fp16 variant)")
362
+ except Exception as e2:
363
+ print(f"❌ Error en segundo intento: {e2}")
364
+ raise e2
365
+ else:
366
+ raise e
367
+ else:
368
+ print(f"♻️ Modelo {model_name} ya está cargado, reutilizando...")
369
+
370
+ return model_cache[model_name]
371
+
372
+ def load_video_model(model_name):
373
+ """Cargar modelo de video con soporte para diferentes tipos"""
374
+ if model_name not in model_cache:
375
+ print(f"Cargando modelo de video: {model_name}")
376
+
377
+ try:
378
+ # Detectar tipo de modelo de video
379
+ if "text-to-video" in model_name.lower():
380
+ # Modelos de texto a video
381
+ from diffusers import DiffusionPipeline
382
+ pipe = DiffusionPipeline.from_pretrained(
383
+ model_name,
384
+ torch_dtype=torch.float32,
385
+ variant="fp16"
386
+ )
387
+ elif "modelscope" in model_name.lower():
388
+ # ModelScope models
389
+ from diffusers import DiffusionPipeline
390
+ pipe = DiffusionPipeline.from_pretrained(
391
+ model_name,
392
+ torch_dtype=torch.float32
393
+ )
394
+ elif "zeroscope" in model_name.lower():
395
+ # Zeroscope models
396
+ from diffusers import DiffusionPipeline
397
+ pipe = DiffusionPipeline.from_pretrained(
398
+ model_name,
399
+ torch_dtype=torch.float32
400
+ )
401
+ elif "animatediff" in model_name.lower():
402
+ # AnimateDiff models
403
+ from diffusers import DiffusionPipeline
404
+ pipe = DiffusionPipeline.from_pretrained(
405
+ model_name,
406
+ torch_dtype=torch.float32
407
+ )
408
+ elif "cogvideo" in model_name.lower():
409
+ # CogVideo models
410
+ from diffusers import DiffusionPipeline
411
+ pipe = DiffusionPipeline.from_pretrained(
412
+ model_name,
413
+ torch_dtype=torch.float32
414
+ )
415
+ elif "pyramid-flow" in model_name.lower():
416
+ # Pyramid Flow models
417
+ from diffusers import DiffusionPipeline
418
+ pipe = DiffusionPipeline.from_pretrained(
419
+ model_name,
420
+ torch_dtype=torch.float32
421
+ )
422
+ else:
423
+ # Fallback a text-to-video genérico
424
+ from diffusers import DiffusionPipeline
425
+ pipe = DiffusionPipeline.from_pretrained(
426
+ model_name,
427
+ torch_dtype=torch.float32
428
+ )
429
+
430
+ # Optimizaciones básicas
431
+ pipe.enable_attention_slicing()
432
+ if hasattr(pipe, 'enable_model_cpu_offload'):
433
+ pipe.enable_model_cpu_offload()
434
+
435
+ model_cache[model_name] = {
436
+ "pipeline": pipe,
437
+ "type": "video"
438
+ }
439
 
440
  except Exception as e:
441
+ print(f"Error cargando modelo de video {model_name}: {e}")
442
+ # Fallback a un modelo básico
443
+ try:
444
+ from diffusers import DiffusionPipeline
445
+ pipe = DiffusionPipeline.from_pretrained(
446
+ "damo-vilab/text-to-video-ms-1.7b",
447
+ torch_dtype=torch.float32
448
+ )
449
+ pipe.enable_attention_slicing()
450
+
451
+ model_cache[model_name] = {
452
+ "pipeline": pipe,
453
+ "type": "video"
454
+ }
455
+ except Exception as fallback_error:
456
+ print(f"Error crítico en fallback de video: {fallback_error}")
457
+ raise
458
 
459
  return model_cache[model_name]
460
 
461
+ @spaces.GPU
462
+ def generate_video(prompt, model_name, num_frames=16, num_inference_steps=20):
463
+ """Generar video con el modelo seleccionado"""
464
+ try:
465
+ print(f"Generando video con modelo: {model_name}")
466
+ print(f"Prompt: {prompt}")
467
+ print(f"Frames: {num_frames}")
468
+ print(f"Pasos: {num_inference_steps}")
469
+
470
+ model_data = load_video_model(model_name)
471
+ pipeline = model_data["pipeline"]
472
+
473
+ # Configuración específica por tipo de modelo
474
+ if "zeroscope" in model_name.lower():
475
+ # Zeroscope models
476
+ result = pipeline(
477
+ prompt,
478
+ num_inference_steps=num_inference_steps,
479
+ num_frames=num_frames,
480
+ height=256,
481
+ width=256
482
+ )
483
+ elif "animatediff" in model_name.lower():
484
+ # AnimateDiff models
485
+ result = pipeline(
486
+ prompt,
487
+ num_inference_steps=num_inference_steps,
488
+ num_frames=num_frames
489
+ )
490
+ else:
491
+ # Text-to-video models (default)
492
+ result = pipeline(
493
+ prompt,
494
+ num_inference_steps=num_inference_steps,
495
+ num_frames=num_frames
496
+ )
497
+
498
+ print("Video generado exitosamente")
499
+
500
+ # Manejar diferentes tipos de respuesta
501
+ if hasattr(result, 'frames'):
502
+ video_frames = result.frames
503
+ elif hasattr(result, 'videos'):
504
+ video_frames = result.videos
505
+ else:
506
+ video_frames = result
507
+
508
+ # Convertir a formato compatible con Gradio
509
+ if isinstance(video_frames, list):
510
+ if len(video_frames) == 1:
511
+ return video_frames[0]
512
+ else:
513
+ return video_frames
514
+ else:
515
+ # Si es un tensor numpy, convertirlo a formato de video
516
+ if hasattr(video_frames, 'shape'):
517
+ import numpy as np
518
+ print(f"Forma del video: {video_frames.shape}")
519
+
520
+ # Convertir a formato de video compatible con Gradio
521
+ if len(video_frames.shape) == 4: # (frames, height, width, channels)
522
+ # Convertir frames a formato de video
523
+ frames_list = []
524
+ for i in range(video_frames.shape[0]):
525
+ frame = video_frames[i]
526
+ # Asegurar que el frame esté en el rango correcto (0-255)
527
+ if frame.dtype == np.float32 or frame.dtype == np.float16:
528
+ frame = (frame * 255).astype(np.uint8)
529
+ frames_list.append(frame)
530
+
531
+ # Crear video a partir de frames
532
+ import imageio
533
+ import tempfile
534
+ import os
535
+
536
+ # Crear archivo temporal
537
+ with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp_file:
538
+ temp_path = tmp_file.name
539
+
540
+ # Guardar frames como video
541
+ imageio.mimsave(temp_path, frames_list, fps=8)
542
+
543
+ print(f"Video guardado en: {temp_path}")
544
+ return temp_path
545
+
546
+ elif len(video_frames.shape) == 5: # (batch, frames, height, width, channels)
547
+ # Tomar el primer batch
548
+ frames = video_frames[0]
549
+ return generate_video(prompt, model_name, num_frames, num_inference_steps)
550
+ else:
551
+ print(f"Forma no reconocida: {video_frames.shape}")
552
+ return None
553
+ else:
554
+ return video_frames
555
+
556
+ except Exception as e:
557
+ print(f"Error generando video: {str(e)}")
558
+ print(f"Tipo de error: {type(e).__name__}")
559
+ import traceback
560
+ traceback.print_exc()
561
+ return f"Error generando video: {str(e)}"
562
+
563
  def generate_text(prompt, model_name, max_length=100):
564
  """Generar texto con el modelo seleccionado"""
565
  try:
 
593
  def generate_image(prompt, model_name, negative_prompt="", seed=0, width=1024, height=1024, guidance_scale=7.5, num_inference_steps=20):
594
  """Generar imagen optimizada para H200"""
595
  try:
596
+ print(f"\n🎨 Iniciando generación de imagen con H200...")
597
+ print(f"📝 Prompt: {prompt}")
598
+ print(f"🚫 Negative prompt: {negative_prompt}")
599
+ print(f"🎯 Modelo seleccionado: {model_name}")
600
+ print(f"🔄 Inference steps: {num_inference_steps}")
601
+ print(f"🎲 Seed: {seed}")
602
+ print(f"📐 Dimensiones: {width}x{height}")
603
+ print(f"🎯 Guidance scale: {guidance_scale}")
604
+
605
+ start_time = time.time()
606
+
607
+ # Convertir parámetros a tipos correctos
608
+ if isinstance(num_inference_steps, str):
609
+ try:
610
+ num_inference_steps = int(num_inference_steps)
611
+ except ValueError:
612
+ num_inference_steps = 20
613
+ print(f"⚠️ No se pudo convertir '{num_inference_steps}' a entero, usando 20")
614
+
615
+ if isinstance(seed, str):
616
+ try:
617
+ seed = int(seed)
618
+ except ValueError:
619
+ seed = 0
620
+ print(f"⚠️ No se pudo convertir '{seed}' a entero, usando 0")
621
+
622
+ if isinstance(width, str):
623
+ try:
624
+ width = int(width)
625
+ except ValueError:
626
+ width = 1024
627
+ print(f"⚠️ No se pudo convertir '{width}' a entero, usando 1024")
628
+
629
+ if isinstance(height, str):
630
+ try:
631
+ height = int(height)
632
+ except ValueError:
633
+ height = 1024
634
+ print(f"⚠️ No se pudo convertir '{height}' a entero, usando 1024")
635
 
636
+ if isinstance(guidance_scale, str):
637
+ try:
638
+ guidance_scale = float(guidance_scale)
639
+ except ValueError:
640
+ guidance_scale = 7.5
641
+ print(f"⚠️ No se pudo convertir '{guidance_scale}' a float, usando 7.5")
642
+
643
+ # Cargar el modelo
644
  pipe = load_image_model(model_name)
645
 
646
+ # Ajustar parámetros según el tipo de modelo
647
+ if "turbo" in model_name.lower():
648
+ guidance_scale = min(guidance_scale, 1.0)
649
+ num_inference_steps = min(num_inference_steps, 4)
650
+ print(f"⚡ Modelo turbo - Ajustando parámetros: guidance={guidance_scale}, steps={num_inference_steps}")
651
+ elif "lightning" in model_name.lower():
652
+ guidance_scale = min(guidance_scale, 1.0)
653
+ num_inference_steps = max(num_inference_steps, 4)
654
+ print(f"⚡ Modelo lightning - Ajustando parámetros: guidance={guidance_scale}, steps={num_inference_steps}")
655
+ elif "flux" in model_name.lower():
656
+ guidance_scale = max(3.5, min(guidance_scale, 7.5))
657
+ num_inference_steps = max(15, num_inference_steps)
658
+ print(f"🔐 Modelo FLUX - Ajustando parámetros: guidance={guidance_scale}, steps={num_inference_steps}")
659
+
660
  generator = torch.Generator(device=device).manual_seed(seed)
661
 
662
+ print("🎨 Iniciando generación de imagen con H200...")
663
+ inference_start = time.time()
664
+
665
+ # Optimizaciones específicas para H200
666
+ if torch.cuda.is_available():
667
+ print("🚀 Aplicando optimizaciones específicas para H200...")
668
+
669
+ # Limpiar cache de GPU antes de la inferencia
670
+ torch.cuda.empty_cache()
671
+
672
+ # Generar la imagen
673
+ print(" Generando imagen con H200...")
674
+
675
+ # Configurar parámetros de generación
676
+ generation_kwargs = {
677
+ "prompt": prompt,
678
+ "height": height,
679
+ "width": width,
680
+ "guidance_scale": guidance_scale,
681
+ "num_inference_steps": num_inference_steps,
682
+ "generator": generator
683
+ }
684
+
685
+ # Agregar parámetros opcionales
686
+ if negative_prompt and negative_prompt.strip():
687
+ generation_kwargs["negative_prompt"] = negative_prompt.strip()
688
+
689
+ # Generar la imagen
690
+ result = pipe(**generation_kwargs)
691
+
692
+ # Verificar que la imagen se generó correctamente
693
+ if hasattr(result, 'images') and len(result.images) > 0:
694
+ image = result.images[0]
695
+
696
+ # Verificar que la imagen no sea completamente negra
697
+ if image is not None:
698
+ # Convertir a numpy para verificar
699
+ img_array = np.array(image)
700
+ if img_array.size > 0:
701
+ # Verificar si la imagen es completamente negra
702
+ if np.all(img_array == 0) or np.all(img_array < 10):
703
+ print("⚠️ ADVERTENCIA: Imagen generada es completamente negra")
704
+ print("🔄 Reintentando con parámetros ajustados...")
705
+
706
+ # Reintentar con parámetros más conservadores
707
+ generation_kwargs["guidance_scale"] = max(1.0, guidance_scale * 0.8)
708
+ generation_kwargs["num_inference_steps"] = max(10, num_inference_steps)
709
+
710
+ result = pipe(**generation_kwargs)
711
+ image = result.images[0]
712
+ else:
713
+ print("✅ Imagen generada correctamente")
714
+ else:
715
+ print("❌ Error: Imagen vacía")
716
+ raise Exception("Imagen vacía generada")
717
+ else:
718
+ print("❌ Error: Imagen es None")
719
+ raise Exception("Imagen es None")
720
+ else:
721
+ print("❌ Error: No se generaron imágenes")
722
+ raise Exception("No se generaron imágenes")
723
+ else:
724
+ # Fallback para CPU
725
+ generation_kwargs = {
726
+ "prompt": prompt,
727
+ "height": height,
728
+ "width": width,
729
+ "guidance_scale": guidance_scale,
730
+ "num_inference_steps": num_inference_steps,
731
+ "generator": generator
732
+ }
733
+
734
+ if negative_prompt and negative_prompt.strip():
735
+ generation_kwargs["negative_prompt"] = negative_prompt.strip()
736
+
737
+ result = pipe(**generation_kwargs)
738
+ image = result.images[0]
739
+
740
+ inference_time = time.time() - inference_start
741
+ total_time = time.time() - start_time
742
+
743
+ print(f"✅ Imagen generada exitosamente con H200!")
744
+ print(f"⏱️ Tiempo de inferencia: {inference_time:.2f} segundos")
745
+ print(f"⏱️ Tiempo total: {total_time:.2f} segundos")
746
+ print(f"🎲 Seed final: {seed}")
747
+
748
+ if torch.cuda.is_available():
749
+ print(f"💾 Memoria GPU utilizada: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")
750
+ print(f"💾 Memoria GPU libre: {torch.cuda.memory_reserved() / 1024**3:.2f} GB")
751
+ print(f"🚀 Velocidad H200: {num_inference_steps/inference_time:.1f} steps/segundo")
752
+ else:
753
+ print("💾 Memoria CPU")
754
+
755
  return image
756
 
757
  except Exception as e:
758
+ print(f"Error en inferencia: {e}")
759
+ print(f"🔍 Tipo de error: {type(e).__name__}")
760
+ print(f"📋 Detalles del error: {str(e)}")
761
+ # Crear imagen de error
762
  error_image = Image.new('RGB', (512, 512), color='red')
763
  return error_image
764
 
 
803
  history.append({"role": "assistant", "content": error_msg})
804
  return history
805
 
806
+ # Verificar acceso a modelos gated
807
+ def check_gated_model_access():
808
+ """Verificar si tenemos acceso a modelos gated"""
809
+ if not HF_TOKEN:
810
+ return False
811
+
812
+ try:
813
+ # Intentar acceder a un modelo gated para verificar permisos
814
+ from huggingface_hub import model_info
815
+ info = model_info("black-forest-labs/FLUX.1-dev", token=HF_TOKEN)
816
+ print(f"✅ Acceso verificado a FLUX.1-dev: {info.modelId}")
817
+ return True
818
+ except Exception as e:
819
+ print(f"❌ No se pudo verificar acceso a modelos gated: {e}")
820
+ return False
821
+
822
+ # Verificar acceso al inicio
823
+ GATED_ACCESS = check_gated_model_access()
824
+
825
+ # Mostrar estado de configuración al inicio
826
+ print("=" * 60)
827
+ print("🚀 SPACE NTIA - ESTADO DE CONFIGURACIÓN")
828
+ print("=" * 60)
829
+ print(f"🔑 Token HF configurado: {'✅' if HF_TOKEN else '❌'}")
830
+ print(f"🔐 Acceso a modelos gated: {'✅' if GATED_ACCESS else '❌'}")
831
+ print(f"🎨 Modelos FLUX disponibles: {'✅' if GATED_ACCESS else '❌'}")
832
+ print("=" * 60)
833
+
834
+ if not GATED_ACCESS:
835
+ print("⚠️ Para usar modelos FLUX:")
836
+ print(" 1. Configura HF_TOKEN en las variables de entorno del Space")
837
+ print(" 2. Solicita acceso a los modelos FLUX en Hugging Face")
838
+ print(" 3. Acepta los términos de licencia")
839
+ print("=" * 60)
840
+
841
  # Interfaz de Gradio
842
  with gr.Blocks(title="Modelos Libres de IA", theme=gr.themes.Soft()) as demo:
843
  gr.Markdown("# 🤖 Modelos Libres de IA")
844
+ gr.Markdown("### Genera texto, imágenes y videos sin límites de cuota")
845
 
846
  with gr.Tabs():
847
  # Tab de Generación de Texto
 
885
  with gr.Row():
886
  with gr.Column():
887
  chat_model = gr.Dropdown(
888
+ choices=list(MODELS["chat"].keys()),
889
  value="microsoft/DialoGPT-medium",
890
  label="Modelo de Chat"
891
  )
 
915
  outputs=[chatbot]
916
  )
917
 
918
+ # Tab de Traducción
919
+ with gr.TabItem("🌐 Traducción"):
920
+ with gr.Row():
921
+ with gr.Column():
922
+ translate_model = gr.Dropdown(
923
+ choices=["Helsinki-NLP/opus-mt-es-en", "Helsinki-NLP/opus-mt-en-es"],
924
+ value="Helsinki-NLP/opus-mt-es-en",
925
+ label="Modelo de Traducción"
926
+ )
927
+ translate_text = gr.Textbox(
928
+ label="Texto a traducir",
929
+ placeholder="Escribe el texto que quieres traducir...",
930
+ lines=3
931
+ )
932
+ translate_btn = gr.Button("Traducir", variant="primary")
933
+
934
+ with gr.Column():
935
+ translate_output = gr.Textbox(
936
+ label="Traducción",
937
+ lines=3,
938
+ interactive=False
939
+ )
940
+
941
+ translate_btn.click(
942
+ generate_text,
943
+ inputs=[translate_text, translate_model, gr.Slider(value=100, visible=False)],
944
+ outputs=translate_output
945
+ )
946
+
947
  # Tab de Generación de Imágenes
948
  with gr.TabItem("🎨 Generación de Imágenes"):
949
  with gr.Row():
950
  with gr.Column():
951
+ # Modelo
952
  image_model = gr.Dropdown(
953
  choices=list(MODELS["image"].keys()),
954
  value="CompVis/stable-diffusion-v1-4",
955
+ label="Modelo",
956
+ info="Select a high-quality model (FLUX models require HF_TOKEN)"
957
  )
958
 
959
+ # Prompt principal
960
  image_prompt = gr.Textbox(
961
  label="Prompt",
962
  placeholder="Describe la imagen que quieres generar...",
963
  lines=3
964
  )
965
 
966
+ # Negative prompt
967
  negative_prompt = gr.Textbox(
968
  label="Negative prompt",
969
  placeholder="Enter a negative prompt (optional)",
970
  lines=2
971
  )
972
 
973
+ # Advanced Settings
974
+ with gr.Accordion("Advanced Settings", open=False):
975
+ with gr.Row():
976
+ with gr.Column():
977
+ seed = gr.Slider(
978
+ minimum=0,
979
+ maximum=2147483647,
980
+ value=324354329,
981
+ step=1,
982
+ label="Seed",
983
+ info="Random seed for generation"
984
+ )
985
+
986
+ with gr.Column():
987
+ guidance_scale = gr.Slider(
988
+ minimum=0,
989
+ maximum=20,
990
+ value=7.5,
991
+ step=0.1,
992
+ label="Guidance scale",
993
+ info="Controls how closely the image follows the prompt (higher = more adherence)"
994
+ )
995
+
996
+ with gr.Row():
997
+ with gr.Column():
998
+ width = gr.Slider(
999
+ minimum=256,
1000
+ maximum=1024,
1001
+ value=1024,
1002
+ step=64,
1003
+ label="Width"
1004
+ )
1005
+ height = gr.Slider(
1006
+ minimum=256,
1007
+ maximum=1024,
1008
+ value=1024,
1009
+ step=64,
1010
+ label="Height"
1011
+ )
1012
+
1013
+ with gr.Column():
1014
+ num_inference_steps = gr.Slider(
1015
+ minimum=1,
1016
+ maximum=100,
1017
+ value=20,
1018
+ step=1,
1019
+ label="Number of inference steps",
1020
+ info="More steps = higher quality but slower generation"
1021
+ )
1022
 
1023
+ # Botón de generación
1024
  image_btn = gr.Button("Generar Imagen", variant="primary")
1025
 
1026
  with gr.Column():
1027
+ # Información del modelo
1028
+ model_info = gr.Markdown(
1029
+ value="**Model Info:** CompVis/stable-diffusion-v1-4\n\n"
1030
+ "🎨 Stable Diffusion v1.4 • Recommended steps: 20-50 • "
1031
+ "Guidance scale: 7.5-15 • Best for: General purpose\n\n"
1032
+ "**Status:** ✅ Available"
1033
+ )
1034
+
1035
+ # Ejemplos
1036
  examples = gr.Examples(
1037
  examples=[
1038
  ["Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"],
1039
  ["An astronaut riding a green horse"],
1040
  ["A delicious ceviche cheesecake slice"],
1041
+ ["Futuristic AI assistant in a glowing galaxy, neon lights, sci-fi style, cinematic"],
1042
+ ["Portrait of a beautiful woman, realistic, high quality, detailed"],
1043
+ ["Anime girl with blue hair, detailed, high quality"],
1044
+ ["Cyberpunk city at night, neon lights, detailed, 8k"],
1045
+ ["Fantasy landscape with mountains and dragons, epic, detailed"]
1046
  ],
1047
  inputs=image_prompt
1048
  )
1049
 
1050
+ # Output de imagen
1051
  image_output = gr.Image(
1052
  label="Imagen Generada",
1053
  type="pil"
1054
  )
1055
 
1056
+ # Función para actualizar info del modelo
1057
+ def update_model_info(model_name):
1058
+ model_descriptions = {
1059
+ "CompVis/stable-diffusion-v1-4": "🎨 Stable Diffusion v1.4 • Recommended steps: 20-50 • Guidance scale: 7.5-15 • Best for: General purpose",
1060
+ "stabilityai/stable-diffusion-2-1": "🎨 Stable Diffusion 2.1 • Recommended steps: 20-50 • Guidance scale: 7.5-15 • Best for: High quality",
1061
+ "stabilityai/stable-diffusion-xl-base-1.0": "🎨 SDXL Base • Recommended steps: 25-50 • Guidance scale: 7.5-15 • Best for: High resolution",
1062
+ "stabilityai/sdxl-turbo": "⚡ SDXL Turbo • Recommended steps: 1-4 • Guidance scale: 1.0 • Best for: Fast generation",
1063
+ "stabilityai/sd-turbo": "⚡ SD Turbo • Recommended steps: 1-4 • Guidance scale: 1.0 • Best for: Fast generation",
1064
+ "black-forest-labs/FLUX.1-dev": "🔐 FLUX Model - High quality • Recommended steps: 20-50 • Guidance scale: 3.5-7.5 • Best for: Professional results",
1065
+ "black-forest-labs/FLUX.1-schnell": "🔐 FLUX Schnell - Fast quality • Recommended steps: 15-30 • Guidance scale: 3.5-7.5 • Best for: Quick professional results"
1066
+ }
1067
+
1068
+ description = model_descriptions.get(model_name, "🎨 Model • Recommended steps: 20-50 • Guidance scale: 7.5-15 • Best for: General purpose")
1069
+ return f"**Model Info:** {model_name}\n\n{description}\n\n**Status:** ✅ Available"
1070
+
1071
+ # Eventos
1072
+ image_model.change(
1073
+ update_model_info,
1074
+ inputs=[image_model],
1075
+ outputs=[model_info]
1076
+ )
1077
+
1078
  image_btn.click(
1079
  generate_image,
1080
  inputs=[
 
1089
  ],
1090
  outputs=image_output
1091
  )
1092
+
1093
+ # Tab de Generación de Videos
1094
+ with gr.TabItem("🎬 Generación de Videos"):
1095
+ with gr.Row():
1096
+ with gr.Column():
1097
+ video_model = gr.Dropdown(
1098
+ choices=list(MODELS["video"].keys()),
1099
+ value="damo-vilab/text-to-video-ms-1.7b",
1100
+ label="Modelo de Video"
1101
+ )
1102
+ video_prompt = gr.Textbox(
1103
+ label="Prompt de Video",
1104
+ placeholder="Describe el video que quieres generar...",
1105
+ lines=3
1106
+ )
1107
+ num_frames = gr.Slider(
1108
+ minimum=8,
1109
+ maximum=32,
1110
+ value=16,
1111
+ step=4,
1112
+ label="Número de frames"
1113
+ )
1114
+ video_steps = gr.Slider(
1115
+ minimum=10,
1116
+ maximum=50,
1117
+ value=20,
1118
+ step=5,
1119
+ label="Pasos de inferencia"
1120
+ )
1121
+ video_btn = gr.Button("Generar Video", variant="primary")
1122
+
1123
+ with gr.Column():
1124
+ video_output = gr.Video(
1125
+ label="Video Generado",
1126
+ format="mp4"
1127
+ )
1128
+
1129
+ video_btn.click(
1130
+ generate_video,
1131
+ inputs=[video_prompt, video_model, num_frames, video_steps],
1132
+ outputs=video_output
1133
+ )
1134
 
1135
  # Configuración para Hugging Face Spaces
1136
  if __name__ == "__main__":