gnosticdev commited on
Commit
60e6f97
verified
1 Parent(s): ab6a3fb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -176
app.py CHANGED
@@ -9,13 +9,15 @@ import re
9
  import torch
10
  from transformers import GPT2LMHeadModel, GPT2Tokenizer
11
  import warnings
 
12
 
13
  # Configuraci贸n inicial
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
- # Suprimir warnings espec铆ficos de transformers
18
  warnings.filterwarnings("ignore", category=UserWarning, module="transformers")
 
19
 
20
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
21
 
@@ -24,245 +26,154 @@ VOICES = [
24
  "es-MX-DaliaNeural", "es-ES-ElviraNeural", "es-AR-ElenaNeural",
25
  "es-MX-JorgeNeural", "es-ES-AlvaroNeural", "es-AR-TomasNeural",
26
  "en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural",
27
- "it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural",
28
- "en-GB-SoniaNeural", "es-CL-CatalinaNeural", "es-CO-GonzaloNeural"
29
  ]
30
 
31
- # Cargar modelo y tokenizador de GPT-2 en espa帽ol
32
- try:
33
- tokenizer = GPT2Tokenizer.from_pretrained("datificate/gpt2-small-spanish")
34
- model = GPT2LMHeadModel.from_pretrained("datificate/gpt2-small-spanish")
35
- logger.info("Modelo GPT-2 en espa帽ol cargado correctamente")
36
- except Exception as e:
37
- logger.error(f"Error cargando el modelo: {str(e)}")
38
- model = None
39
- tokenizer = None
 
40
 
41
- def generar_guion_largo(tema, custom_script=None):
42
- """Genera un texto largo sobre el tema usando GPT-2 con configuraci贸n correcta"""
 
 
43
  if custom_script:
44
  return custom_script
45
-
46
  if model is None or tokenizer is None:
47
- return f"Texto generado autom谩ticamente sobre {tema}. " * 50
48
 
49
  try:
50
- # Prompt directo como solicitaste
51
- prompt = f"Escribe un texto largo y detallado sobre {tema}"
52
-
53
- inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
54
 
55
- # Generar texto con configuraci贸n corregida
56
  outputs = model.generate(
57
  inputs.input_ids,
58
- max_length=800,
59
  do_sample=True,
60
- temperature=0.9,
61
  top_k=50,
62
- top_p=0.95,
63
  num_return_sequences=1,
64
- pad_token_id=tokenizer.eos_token_id,
65
- # early_stopping=True # Eliminado para evitar warnings
66
  )
67
 
68
- guion = tokenizer.decode(outputs[0], skip_special_tokens=True)
69
-
70
- # Limpiar texto
71
- guion = re.sub(r'<.*?>', '', guion)
72
- guion = re.sub(r'\n+', '\n', guion)
73
- guion = re.sub(r'\s+', ' ', guion).strip()
74
-
75
- logger.info(f"Guion generado: {len(guion)} caracteres")
76
- return guion
77
-
78
  except Exception as e:
79
- logger.error(f"Error generando guion: {str(e)}")
80
- return f"Texto generado autom谩ticamente sobre {tema}. " * 50
81
 
82
- def buscar_videos_pexels(tema, num_videos=4):
83
- """Busca videos en Pexels usando el tema directamente"""
84
  try:
85
  headers = {"Authorization": PEXELS_API_KEY}
86
-
87
- logger.info(f"Buscando videos para: {tema}")
88
-
89
  response = requests.get(
90
- f"https://api.pexels.com/videos/search?query={tema}&per_page={num_videos}",
91
  headers=headers,
92
- timeout=15
93
  )
94
-
95
- if response.status_code != 200:
96
- return []
97
-
98
- return response.json().get("videos", [])[:num_videos]
99
  except Exception as e:
100
  logger.error(f"Error buscando videos: {str(e)}")
101
  return []
102
 
103
- def descargar_video(url, output_path):
104
- """Descarga un video de manera eficiente"""
105
- try:
106
- with requests.get(url, stream=True, timeout=30) as r:
107
- r.raise_for_status()
108
- with open(output_path, 'wb') as f:
109
- for chunk in r.iter_content(chunk_size=8192):
110
- f.write(chunk)
111
- return True
112
- except Exception as e:
113
- logger.error(f"Error descargando video: {str(e)}")
114
- return False
115
-
116
  def crear_video(prompt, custom_script, voz_seleccionada, musica=None):
117
  try:
118
- # 1. Generar guion largo
119
- guion = generar_guion_largo(prompt, custom_script)
 
 
 
120
 
121
- # 2. Generar narraci贸n
122
- voz_archivo = "voz.mp3"
123
  subprocess.run([
124
  'edge-tts',
125
  '--voice', voz_seleccionada,
126
  '--text', guion,
127
- '--write-media', voz_archivo
128
  ], check=True)
129
 
130
- # 3. Procesar audio principal
131
- audio = AudioFileClip(voz_archivo)
132
- duracion_total = audio.duration
133
-
134
- # 4. Buscar videos relevantes
135
- videos_data = buscar_videos_pexels(prompt)
136
-
137
- if not videos_data:
138
- logger.warning("No se encontraron videos. Usando videos gen茅ricos...")
139
- videos_data = buscar_videos_pexels("nature")
140
 
141
- # 5. Descargar y preparar videos
 
142
  clips = []
143
- for i, video in enumerate(videos_data):
 
144
  try:
145
- # Seleccionar la mejor calidad disponible
146
- if 'video_files' not in video or not video['video_files']:
147
- continue
148
-
149
- video_file = max(
150
- video['video_files'],
151
- key=lambda x: x.get('width', 0) * x.get('height', 0)
152
- )
153
- video_url = video_file['link']
154
- temp_path = f"temp_video_{i}.mp4"
155
 
156
- if descargar_video(video_url, temp_path):
157
- clip = VideoFileClip(temp_path)
158
-
159
- # Calcular duraci贸n proporcional para cada clip
160
- duracion_clip = duracion_total / len(videos_data)
161
-
162
- # Ajustar clip a la duraci贸n requerida
163
- if clip.duration < duracion_clip:
164
- clip = clip.loop(duration=duracion_clip)
165
- else:
166
- clip = clip.subclip(0, duracion_clip)
167
-
168
- clips.append(clip)
169
  except Exception as e:
170
  logger.error(f"Error procesando video {i}: {str(e)}")
171
 
 
172
  if not clips:
173
- # Crear video de fondo negro si no hay videos
174
- clip = ColorClip(size=(1280, 720), color=(0, 0, 0), duration=duracion_total)
175
- clips = [clip]
176
 
177
- # 6. Combinar videos
178
- final_clip = concatenate_videoclips(clips, method="compose")
179
  final_clip = final_clip.set_audio(audio)
180
 
181
- # 7. Aplicar m煤sica de fondo si existe
182
- if musica:
183
- try:
184
- musica_clip = AudioFileClip(musica.name)
185
- if musica_clip.duration < duracion_total:
186
- musica_clip = musica_clip.loop(duration=duracion_total)
187
- else:
188
- musica_clip = musica_clip.subclip(0, duracion_total)
189
-
190
- audio_final = CompositeAudioClip([
191
- audio.volumex(1.0),
192
- musica_clip.volumex(0.25)
193
- ])
194
- final_clip = final_clip.set_audio(audio_final)
195
- except Exception as e:
196
- logger.error(f"Error procesando m煤sica: {str(e)}")
197
-
198
- # 8. Exportar video final
199
- output_path = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
200
  final_clip.write_videofile(
201
- output_path,
202
  fps=24,
203
  codec="libx264",
204
  audio_codec="aac",
205
- threads=4,
206
  preset='fast'
207
  )
208
 
209
- logger.info(f"Video generado exitosamente: {output_path}")
210
- return output_path
211
 
212
  except Exception as e:
213
- logger.error(f"ERROR: {str(e)}")
214
  return None
215
  finally:
216
- # Limpieza garantizada
217
- if os.path.exists(voz_archivo):
218
- os.remove(voz_archivo)
219
- for i in range(5):
220
- temp_file = f"temp_video_{i}.mp4"
221
- if os.path.exists(temp_file):
222
- os.remove(temp_file)
223
 
224
- # Interfaz mejorada
225
- with gr.Blocks(title="Generador de Videos", theme=gr.themes.Soft()) as app:
226
- gr.Markdown("# 馃幀 GENERADOR AUTOM脕TICO DE VIDEOS")
227
-
228
  with gr.Row():
229
  with gr.Column():
230
- prompt = gr.Textbox(
231
- label="Tema del video",
232
- placeholder="Ej: 'La historia de la pirater铆a en el Caribe'",
233
- max_lines=1
234
- )
235
- custom_script = gr.TextArea(
236
- label="Guion personalizado (opcional)",
237
- placeholder="Pega tu guion completo aqu铆...",
238
- lines=8,
239
- max_lines=20
240
- )
241
- voz = gr.Dropdown(
242
- label="Voz Narradora",
243
- choices=VOICES,
244
- value=VOICES[0],
245
- interactive=True
246
- )
247
- musica = gr.File(
248
- label="M煤sica de fondo (opcional)",
249
- file_types=["audio"],
250
- type="filepath"
251
- )
252
- btn = gr.Button("Generar Video", variant="primary")
253
-
254
  with gr.Column():
255
- output = gr.Video(
256
- label="Video Resultado",
257
- format="mp4",
258
- interactive=False
259
- )
260
-
261
  btn.click(
262
  fn=crear_video,
263
- inputs=[prompt, custom_script, voz, musica],
264
- outputs=output
265
  )
266
 
267
  if __name__ == "__main__":
268
- app.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
9
  import torch
10
  from transformers import GPT2LMHeadModel, GPT2Tokenizer
11
  import warnings
12
+ import time
13
 
14
  # Configuraci贸n inicial
15
  logging.basicConfig(level=logging.INFO)
16
  logger = logging.getLogger(__name__)
17
 
18
+ # Suprimir warnings espec铆ficos
19
  warnings.filterwarnings("ignore", category=UserWarning, module="transformers")
20
+ warnings.filterwarnings("ignore", category=DeprecationWarning)
21
 
22
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
23
 
 
26
  "es-MX-DaliaNeural", "es-ES-ElviraNeural", "es-AR-ElenaNeural",
27
  "es-MX-JorgeNeural", "es-ES-AlvaroNeural", "es-AR-TomasNeural",
28
  "en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural",
29
+ "it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural"
 
30
  ]
31
 
32
+ # Cargar modelo GPT-2 con manejo de errores mejorado
33
+ def cargar_modelo():
34
+ try:
35
+ tokenizer = GPT2Tokenizer.from_pretrained("datificate/gpt2-small-spanish")
36
+ model = GPT2LMHeadModel.from_pretrained("datificate/gpt2-small-spanish")
37
+ logger.info("Modelo GPT-2 cargado correctamente")
38
+ return tokenizer, model
39
+ except Exception as e:
40
+ logger.error(f"Error cargando modelo: {str(e)}")
41
+ return None, None
42
 
43
+ tokenizer, model = cargar_modelo()
44
+
45
+ def generar_guion(tema, custom_script=None):
46
+ """Genera texto basado en el tema sin estructuras predefinidas"""
47
  if custom_script:
48
  return custom_script
49
+
50
  if model is None or tokenizer is None:
51
+ return f"Texto sobre {tema}. " * 100
52
 
53
  try:
54
+ inputs = tokenizer(f"Escribe un texto largo sobre {tema}", return_tensors="pt", truncation=True)
 
 
 
55
 
 
56
  outputs = model.generate(
57
  inputs.input_ids,
58
+ max_length=1000,
59
  do_sample=True,
60
+ temperature=0.7,
61
  top_k=50,
 
62
  num_return_sequences=1,
63
+ pad_token_id=tokenizer.eos_token_id
 
64
  )
65
 
66
+ return tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 
 
 
 
 
 
 
 
67
  except Exception as e:
68
+ logger.error(f"Error generando texto: {str(e)}")
69
+ return f"Contenido generado sobre {tema}. " * 100
70
 
71
+ def buscar_videos(tema):
72
+ """Busca videos en Pexels con manejo de errores mejorado"""
73
  try:
74
  headers = {"Authorization": PEXELS_API_KEY}
 
 
 
75
  response = requests.get(
76
+ f"https://api.pexels.com/videos/search?query={tema}&per_page=3",
77
  headers=headers,
78
+ timeout=10
79
  )
80
+ return response.json().get("videos", [])[:3]
 
 
 
 
81
  except Exception as e:
82
  logger.error(f"Error buscando videos: {str(e)}")
83
  return []
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  def crear_video(prompt, custom_script, voz_seleccionada, musica=None):
86
  try:
87
+ start_time = time.time()
88
+
89
+ # 1. Generar gui贸n
90
+ guion = generar_guion(prompt, custom_script)
91
+ logger.info(f"Guion generado ({len(guion)} caracteres)")
92
 
93
+ # 2. Generar voz
94
+ voz_file = "narracion.mp3"
95
  subprocess.run([
96
  'edge-tts',
97
  '--voice', voz_seleccionada,
98
  '--text', guion,
99
+ '--write-media', voz_file
100
  ], check=True)
101
 
102
+ audio = AudioFileClip(voz_file)
103
+ duracion = audio.duration
 
 
 
 
 
 
 
 
104
 
105
+ # 3. Buscar y descargar videos
106
+ videos = buscar_videos(prompt) or buscar_videos("nature")
107
  clips = []
108
+
109
+ for i, video in enumerate(videos):
110
  try:
111
+ video_file = max(video['video_files'], key=lambda x: x.get('width', 0))
112
+ temp_file = f"temp_vid_{i}.mp4"
113
+
114
+ with requests.get(video_file['link'], stream=True) as r:
115
+ r.raise_for_status()
116
+ with open(temp_file, 'wb') as f:
117
+ for chunk in r.iter_content(chunk_size=8192):
118
+ f.write(chunk)
 
 
119
 
120
+ clip = VideoFileClip(temp_file)
121
+ clip = clip.subclip(0, min(10, clip.duration)) # M谩ximo 10 segundos por clip
122
+ clips.append(clip)
 
 
 
 
 
 
 
 
 
 
123
  except Exception as e:
124
  logger.error(f"Error procesando video {i}: {str(e)}")
125
 
126
+ # 4. Crear video final
127
  if not clips:
128
+ final_clip = ColorClip((1280, 720), (0, 0, 0), duration=duracion)
129
+ else:
130
+ final_clip = concatenate_videoclips(clips).set_duration(duracion)
131
 
 
 
132
  final_clip = final_clip.set_audio(audio)
133
 
134
+ output_file = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  final_clip.write_videofile(
136
+ output_file,
137
  fps=24,
138
  codec="libx264",
139
  audio_codec="aac",
140
+ threads=2,
141
  preset='fast'
142
  )
143
 
144
+ logger.info(f"Video creado en {time.time()-start_time:.2f} segundos")
145
+ return output_file
146
 
147
  except Exception as e:
148
+ logger.error(f"Error cr铆tico: {str(e)}")
149
  return None
150
  finally:
151
+ # Limpieza
152
+ for f in [voz_file, *[f"temp_vid_{i}.mp4" for i in range(3)]]:
153
+ if os.path.exists(f):
154
+ os.remove(f)
 
 
 
155
 
156
+ # Interfaz simplificada y funcional
157
+ with gr.Blocks(title="Generador de Videos") as app:
 
 
158
  with gr.Row():
159
  with gr.Column():
160
+ tema = gr.Textbox(label="Tema del video")
161
+ guion = gr.TextArea(label="Guion personalizado (opcional)", lines=5)
162
+ voz = gr.Dropdown(label="Voz", choices=VOICES, value=VOICES[0])
163
+ btn = gr.Button("Generar Video")
164
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  with gr.Column():
166
+ salida = gr.Video(label="Resultado")
167
+
 
 
 
 
168
  btn.click(
169
  fn=crear_video,
170
+ inputs=[tema, guion, voz],
171
+ outputs=salida
172
  )
173
 
174
  if __name__ == "__main__":
175
+ app.launch(
176
+ server_name="0.0.0.0",
177
+ server_port=7860,
178
+ share=False # Desactivado para evitar problemas
179
+ )