gnosticdev commited on
Commit
9143db2
verified
1 Parent(s): 384cc5a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -109
app.py CHANGED
@@ -4,17 +4,12 @@ import requests
4
  import gradio as gr
5
  from moviepy.editor import *
6
  from datetime import datetime
7
- import tempfile
8
  import logging
9
- from transformers import pipeline
10
- import nltk
11
- from nltk.tokenize import sent_tokenize
12
- import numpy as np
13
- from sklearn.feature_extraction.text import TfidfVectorizer
14
  import re
 
 
15
 
16
  # Configuraci贸n inicial
17
- nltk.download('punkt', quiet=True)
18
  logging.basicConfig(level=logging.INFO)
19
  logger = logging.getLogger(__name__)
20
 
@@ -23,77 +18,69 @@ PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
23
  # Lista de voces v谩lidas
24
  VOICES = [
25
  "es-MX-DaliaNeural", "es-ES-ElviraNeural", "es-AR-ElenaNeural",
 
26
  "en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural",
27
- "it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural"
 
28
  ]
29
 
30
- # Inicializar el generador de texto
31
  try:
32
- script_generator = pipeline(
33
- "text-generation",
34
- model="gpt2", # Modelo m谩s flexible
35
- device=0 if torch.cuda.is_available() else -1
36
- )
37
- except:
38
- logger.warning("No se pudo cargar el modelo de generaci贸n de texto")
39
- script_generator = None
40
-
41
- def generar_guion(prompt):
42
- """Genera un guion natural y extenso basado en el prompt"""
43
- if script_generator:
44
- try:
45
- result = script_generator(
46
- f"Genera un texto detallado y bien estructurado sobre '{prompt}' para un video de YouTube:",
47
- max_length=500, # Texto m谩s largo
48
- temperature=0.9, # M谩s creatividad
49
- num_return_sequences=1
50
- )
51
- guion = result[0]['generated_text']
52
-
53
- # Limpiar el guion generado
54
- guion = re.sub(r'<.*?>', '', guion)
55
- guion = re.sub(r'\n+', '\n', guion)
56
- return guion.strip()
57
- except Exception as e:
58
- logger.error(f"Error generando guion: {str(e)}")
59
-
60
- # Fallback natural
61
- return f"En este video exploraremos en profundidad el tema de {prompt}. " \
62
- "Analizaremos diversos aspectos y perspectivas para ofrecer una visi贸n completa. " \
63
- "Veremos c贸mo este tema se relaciona con nuestra vida cotidiana y su impacto en la sociedad actual."
64
 
65
- def extraer_palabras_clave(texto, n=7):
66
- """Extrae palabras clave relevantes usando TF-IDF"""
67
- # Preprocesamiento del texto
68
- texto = re.sub(r'[^\w\s]', '', texto.lower())
69
-
70
- # Tokenizar en oraciones
71
- oraciones = sent_tokenize(texto)
72
-
73
- # Crear matriz TF-IDF
74
- vectorizer = TfidfVectorizer(
75
- stop_words=['el', 'la', 'los', 'las', 'de', 'en', 'y', 'que', 'un', 'una', 'con', 'para'],
76
- max_features=500
77
- )
78
- X = vectorizer.fit_transform(oraciones)
79
-
80
- # Obtener palabras con mayor puntuaci贸n TF-IDF
81
- suma_scores = np.asarray(X.sum(axis=0)).ravel()
82
- indices = np.argsort(suma_scores)[::-1][:n]
83
- palabras = vectorizer.get_feature_names_out()
84
 
85
- return [palabras[i] for i in indices]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
- def buscar_videos_pexels(palabras_clave, num_videos=3):
88
- """Busca videos en Pexels usando palabras clave con enfoque en relevancia"""
89
  try:
90
  headers = {"Authorization": PEXELS_API_KEY}
91
- query = "+".join(palabras_clave[:3]) # Usar las 3 palabras m谩s relevantes
92
 
93
- logger.info(f"Buscando videos con palabras clave: {query}")
94
 
95
  response = requests.get(
96
- f"https://api.pexels.com/videos/search?query={query}&per_page={num_videos}",
97
  headers=headers,
98
  timeout=15
99
  )
@@ -102,7 +89,7 @@ def buscar_videos_pexels(palabras_clave, num_videos=3):
102
  # Filtrar videos de alta calidad
103
  return sorted(
104
  videos,
105
- key=lambda x: x.get('duration', 0),
106
  reverse=True
107
  )[:num_videos]
108
  except Exception as e:
@@ -112,7 +99,7 @@ def buscar_videos_pexels(palabras_clave, num_videos=3):
112
  def descargar_video(url, output_path):
113
  """Descarga un video de manera eficiente"""
114
  try:
115
- with requests.get(url, stream=True, timeout=25) as r:
116
  r.raise_for_status()
117
  with open(output_path, 'wb') as f:
118
  for chunk in r.iter_content(chunk_size=8192):
@@ -124,21 +111,10 @@ def descargar_video(url, output_path):
124
 
125
  def crear_video(prompt, custom_script, voz_seleccionada, musica=None):
126
  try:
127
- # 1. Generar guion natural
128
- guion = custom_script if custom_script else generar_guion(prompt)
129
- logger.info(f"Guion generado ({len(guion)} caracteres)")
130
-
131
- # 2. Extraer palabras clave del guion completo
132
- palabras_clave = extraer_palabras_clave(guion)
133
- logger.info(f"Palabras clave extra铆das: {', '.join(palabras_clave)}")
134
 
135
- # 3. Buscar videos relevantes usando IA
136
- videos_data = buscar_videos_pexels(palabras_clave)
137
-
138
- if not videos_data:
139
- raise Exception("No se encontraron videos relevantes. Usando backup...")
140
-
141
- # 4. Generar narraci贸n
142
  voz_archivo = "voz.mp3"
143
  subprocess.run([
144
  'edge-tts',
@@ -147,70 +123,100 @@ def crear_video(prompt, custom_script, voz_seleccionada, musica=None):
147
  '--write-media', voz_archivo
148
  ], check=True)
149
 
150
- # 5. Procesar audio
151
  audio = AudioFileClip(voz_archivo)
152
  duracion_total = audio.duration
153
 
154
- # 6. Descargar y preparar videos
 
 
 
 
 
 
 
155
  clips = []
156
  for i, video in enumerate(videos_data):
157
- # Seleccionar la mejor calidad
158
- video_file = max(
159
- video['video_files'],
160
- key=lambda x: x.get('width', 0) * x.get('height', 0)
161
- )
162
- video_url = video_file['link']
163
- temp_path = f"temp_video_{i}.mp4"
164
-
165
- if descargar_video(video_url, temp_path):
166
- clip = VideoFileClip(temp_path)
167
 
168
- # Ajustar duraci贸n proporcional
169
- duracion_clip = min(duracion_total / len(videos_data), clip.duration)
170
- clips.append(clip.subclip(0, duracion_clip))
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
- # 7. Combinar videos
 
 
 
173
  video_final = concatenate_videoclips(clips)
174
  video_final = video_final.set_audio(audio)
175
 
176
- # 8. Exportar
177
  output_path = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
178
  video_final.write_videofile(
179
  output_path,
180
  fps=24,
181
  codec="libx264",
182
  audio_codec="aac",
183
- threads=2
 
184
  )
185
 
 
186
  return output_path
187
 
188
  except Exception as e:
189
  logger.error(f"ERROR: {str(e)}")
190
  return None
191
  finally:
192
- # Limpieza
193
  if os.path.exists(voz_archivo):
194
  os.remove(voz_archivo)
195
- for i in range(3):
196
  temp_file = f"temp_video_{i}.mp4"
197
  if os.path.exists(temp_file):
198
  os.remove(temp_file)
199
 
200
  # Interfaz simplificada y funcional
201
  with gr.Blocks(title="Generador de Videos") as app:
202
- gr.Markdown("# 馃帴 Generador Autom谩tico de Videos")
203
 
204
  with gr.Row():
205
- prompt = gr.Textbox(label="Tema del video", placeholder="Ej: Exploraci贸n espacial")
206
- voz = gr.Dropdown(label="Voz Narradora", choices=VOICES, value=VOICES[0])
207
-
208
- btn = gr.Button("Generar Video", variant="primary")
209
- output = gr.Video(label="Resultado", format="mp4")
 
 
 
 
 
 
 
 
210
 
211
  btn.click(
212
  fn=crear_video,
213
- inputs=[prompt, gr.Textbox(visible=False), voz, gr.File(visible=False)],
214
  outputs=output
215
  )
216
 
 
4
  import gradio as gr
5
  from moviepy.editor import *
6
  from datetime import datetime
 
7
  import logging
 
 
 
 
 
8
  import re
9
+ import torch
10
+ from transformers import GPT2LMHeadModel, GPT2Tokenizer
11
 
12
  # Configuraci贸n inicial
 
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger(__name__)
15
 
 
18
  # Lista de voces v谩lidas
19
  VOICES = [
20
  "es-MX-DaliaNeural", "es-ES-ElviraNeural", "es-AR-ElenaNeural",
21
+ "es-MX-JorgeNeural", "es-ES-AlvaroNeural", "es-AR-TomasNeural",
22
  "en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural",
23
+ "it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural",
24
+ "en-GB-SoniaNeural", "es-CL-CatalinaNeural", "es-CO-GonzaloNeural"
25
  ]
26
 
27
+ # Cargar modelo y tokenizador de GPT-2 en espa帽ol
28
  try:
29
+ tokenizer = GPT2Tokenizer.from_pretrained("datificate/gpt2-small-spanish")
30
+ model = GPT2LMHeadModel.from_pretrained("datificate/gpt2-small-spanish")
31
+ logger.info("Modelo GPT-2 en espa帽ol cargado correctamente")
32
+ except Exception as e:
33
+ logger.error(f"Error cargando el modelo: {str(e)}")
34
+ model = None
35
+ tokenizer = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ def generar_guion_largo(tema, custom_script=None):
38
+ """Genera un texto largo sobre el tema usando GPT-2"""
39
+ if custom_script:
40
+ return custom_script
41
+
42
+ if model is None or tokenizer is None:
43
+ return f"Texto generado autom谩ticamente sobre {tema}. " * 50
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ try:
46
+ # Prompt directo como solicitaste
47
+ prompt = f"Escribe un texto largo y detallado sobre {tema}"
48
+
49
+ inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
50
+
51
+ # Generar texto
52
+ outputs = model.generate(
53
+ inputs.input_ids,
54
+ max_length=800,
55
+ temperature=0.9,
56
+ top_k=50,
57
+ top_p=0.95,
58
+ num_return_sequences=1,
59
+ pad_token_id=tokenizer.eos_token_id
60
+ )
61
+
62
+ guion = tokenizer.decode(outputs[0], skip_special_tokens=True)
63
+
64
+ # Limpiar texto
65
+ guion = re.sub(r'<.*?>', '', guion)
66
+ guion = re.sub(r'\n+', '\n', guion)
67
+
68
+ logger.info(f"Guion generado: {len(guion)} caracteres")
69
+ return guion
70
+
71
+ except Exception as e:
72
+ logger.error(f"Error generando guion: {str(e)}")
73
+ return f"Texto generado autom谩ticamente sobre {tema}. " * 50
74
 
75
+ def buscar_videos_pexels(tema, num_videos=4):
76
+ """Busca videos en Pexels usando el tema directamente"""
77
  try:
78
  headers = {"Authorization": PEXELS_API_KEY}
 
79
 
80
+ logger.info(f"Buscando videos para: {tema}")
81
 
82
  response = requests.get(
83
+ f"https://api.pexels.com/videos/search?query={tema}&per_page={num_videos}",
84
  headers=headers,
85
  timeout=15
86
  )
 
89
  # Filtrar videos de alta calidad
90
  return sorted(
91
  videos,
92
+ key=lambda x: (x.get('width', 0) * x.get('height', 0), x.get('duration', 0)),
93
  reverse=True
94
  )[:num_videos]
95
  except Exception as e:
 
99
  def descargar_video(url, output_path):
100
  """Descarga un video de manera eficiente"""
101
  try:
102
+ with requests.get(url, stream=True, timeout=30) as r:
103
  r.raise_for_status()
104
  with open(output_path, 'wb') as f:
105
  for chunk in r.iter_content(chunk_size=8192):
 
111
 
112
  def crear_video(prompt, custom_script, voz_seleccionada, musica=None):
113
  try:
114
+ # 1. Generar guion largo
115
+ guion = generar_guion_largo(prompt, custom_script)
 
 
 
 
 
116
 
117
+ # 2. Generar narraci贸n
 
 
 
 
 
 
118
  voz_archivo = "voz.mp3"
119
  subprocess.run([
120
  'edge-tts',
 
123
  '--write-media', voz_archivo
124
  ], check=True)
125
 
126
+ # 3. Procesar audio principal
127
  audio = AudioFileClip(voz_archivo)
128
  duracion_total = audio.duration
129
 
130
+ # 4. Buscar videos relevantes
131
+ videos_data = buscar_videos_pexels(prompt)
132
+
133
+ if not videos_data:
134
+ logger.warning("No se encontraron videos. Usando videos gen茅ricos...")
135
+ videos_data = buscar_videos_pexels("nature")
136
+
137
+ # 5. Descargar y preparar videos
138
  clips = []
139
  for i, video in enumerate(videos_data):
140
+ try:
141
+ # Seleccionar la mejor calidad disponible
142
+ video_file = max(
143
+ video['video_files'],
144
+ key=lambda x: x.get('width', 0) * x.get('height', 0)
145
+ )
146
+ video_url = video_file['link']
147
+ temp_path = f"temp_video_{i}.mp4"
 
 
148
 
149
+ if descargar_video(video_url, temp_path):
150
+ clip = VideoFileClip(temp_path)
151
+
152
+ # Calcular duraci贸n proporcional para cada clip
153
+ duracion_clip = duracion_total / len(videos_data)
154
+
155
+ # Ajustar clip a la duraci贸n requerida
156
+ if clip.duration < duracion_clip:
157
+ clip = clip.loop(duration=duracion_clip)
158
+ else:
159
+ clip = clip.subclip(0, duracion_clip)
160
+
161
+ clips.append(clip)
162
+ except Exception as e:
163
+ logger.error(f"Error procesando video {i}: {str(e)}")
164
 
165
+ if not clips:
166
+ raise Exception("No se pudieron cargar videos v谩lidos")
167
+
168
+ # 6. Combinar videos
169
  video_final = concatenate_videoclips(clips)
170
  video_final = video_final.set_audio(audio)
171
 
172
+ # 7. Exportar video final
173
  output_path = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
174
  video_final.write_videofile(
175
  output_path,
176
  fps=24,
177
  codec="libx264",
178
  audio_codec="aac",
179
+ threads=4,
180
+ preset='fast'
181
  )
182
 
183
+ logger.info(f"Video generado exitosamente: {output_path}")
184
  return output_path
185
 
186
  except Exception as e:
187
  logger.error(f"ERROR: {str(e)}")
188
  return None
189
  finally:
190
+ # Limpieza garantizada
191
  if os.path.exists(voz_archivo):
192
  os.remove(voz_archivo)
193
+ for i in range(5):
194
  temp_file = f"temp_video_{i}.mp4"
195
  if os.path.exists(temp_file):
196
  os.remove(temp_file)
197
 
198
  # Interfaz simplificada y funcional
199
  with gr.Blocks(title="Generador de Videos") as app:
200
+ gr.Markdown("# 馃幀 GENERADOR AUTOM脕TICO DE VIDEOS")
201
 
202
  with gr.Row():
203
+ with gr.Column():
204
+ prompt = gr.Textbox(label="Tema del video", placeholder="Ej: 'La historia de la inteligencia artificial'")
205
+ custom_script = gr.TextArea(
206
+ label="Guion personalizado (opcional)",
207
+ placeholder="Pega tu guion completo aqu铆...",
208
+ lines=5
209
+ )
210
+ voz = gr.Dropdown(label="Voz Narradora", choices=VOICES, value=VOICES[0])
211
+ musica = gr.File(label="M煤sica de fondo (opcional)", file_types=["audio"])
212
+ btn = gr.Button("Generar Video", variant="primary")
213
+
214
+ with gr.Column():
215
+ output = gr.Video(label="Video Resultado", format="mp4")
216
 
217
  btn.click(
218
  fn=crear_video,
219
+ inputs=[prompt, custom_script, voz, musica],
220
  outputs=output
221
  )
222