gnosticdev commited on
Commit
4cf7ad9
verified
1 Parent(s): 78a3857

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -49
app.py CHANGED
@@ -17,23 +17,19 @@ from google.oauth2 import service_account
17
  from googleapiclient.http import MediaFileUpload
18
  from io import BytesIO
19
 
20
- # Crear el archivo de credenciales de servicio desde los secretos
21
  service_account_info = json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT', '{}'))
22
  if service_account_info:
23
  with open('service-account.json', 'w') as f:
24
  json.dump(service_account_info, f)
25
 
26
- # Define la carpeta de salida y la carpeta temporal
27
  output_folder = "outputs"
28
  temp_dir = "temp_files"
29
  os.makedirs(output_folder, exist_ok=True)
30
  os.makedirs(temp_dir, exist_ok=True)
31
 
32
- # ID de la carpeta de destino en Google Drive
33
- FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3" # Reemplaza con tu ID de carpeta
34
 
35
  def cleanup_temp_files():
36
- """Elimina todos los archivos temporales de la carpeta temp_files."""
37
  for filename in os.listdir(temp_dir):
38
  file_path = os.path.join(temp_dir, filename)
39
  try:
@@ -43,55 +39,114 @@ def cleanup_temp_files():
43
  print(f"Error deleting {file_path}: {e}")
44
 
45
  def resize_and_blur_video(clip, target_width=1920, target_height=1080):
46
- """Redimensiona el video al tama帽o 1080p (16:9) y aplica desenfoque si es necesario."""
47
- # (c贸digo existente)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  def download_video(link):
50
- """Descarga un video desde un enlace y lo guarda en la carpeta temporal."""
51
- # (c贸digo existente)
 
 
 
 
 
 
 
 
 
52
 
53
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
54
- """Concatena videos de Pixabay basados en palabras clave."""
55
- # (c贸digo existente)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  def adjust_background_music(video_duration, music_file):
58
- """Ajusta la m煤sica de fondo para que coincida con la duraci贸n del video."""
59
- # (c贸digo existente)
 
 
 
 
 
 
 
 
 
60
 
61
  def combine_audio_video(audio_file, video_clip, music_clip=None):
62
- """Combina el audio y el video en un archivo final."""
63
  try:
64
  audio_clip = AudioFileClip(audio_file)
65
- total_duration = audio_clip.duration + 2 # A帽adimos 2 segundos extra
66
 
67
- # Aseguramos que el video tenga la duraci贸n correcta
68
  video_clip = video_clip.loop(duration=total_duration)
69
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
70
 
71
- # Combinamos el audio principal
72
  final_clip = video_clip.set_audio(audio_clip)
73
-
74
- # A帽adimos la m煤sica de fondo si existe
75
  if music_clip:
76
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
77
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
78
-
79
- # Generamos el nombre del archivo y la ruta
80
  output_filename = f"final_video_{int(time.time())}.mp4"
81
  output_path = os.path.join(output_folder, output_filename)
82
-
83
- # Guardamos el video
84
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
85
-
86
- # Limpiamos los clips
87
  final_clip.close()
88
  video_clip.close()
89
  audio_clip.close()
90
  if music_clip:
91
  music_clip.close()
92
-
93
  return output_path
94
-
95
  except Exception as e:
96
  print(f"Error combinando audio y video: {e}")
97
  if 'final_clip' in locals():
@@ -99,15 +154,12 @@ def combine_audio_video(audio_file, video_clip, music_clip=None):
99
  return None
100
 
101
  def upload_to_google_drive(file_path, folder_id):
102
- """Sube un archivo a Google Drive y devuelve el enlace p煤blico."""
103
  try:
104
- # Autenticaci贸n
105
  creds = service_account.Credentials.from_service_account_file(
106
  'service-account.json', scopes=['https://www.googleapis.com/auth/drive']
107
  )
108
  service = build('drive', 'v3', credentials=creds)
109
 
110
- # Subir el archivo
111
  file_metadata = {
112
  'name': os.path.basename(file_path),
113
  'parents': [folder_id]
@@ -115,14 +167,12 @@ def upload_to_google_drive(file_path, folder_id):
115
  media = MediaFileUpload(file_path, resumable=True)
116
  file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
117
 
118
- # Hacer el archivo p煤blico
119
  permission = {
120
  'type': 'anyone',
121
  'role': 'reader'
122
  }
123
  service.permissions().create(fileId=file['id'], body=permission).execute()
124
 
125
- # Generar el enlace de descarga
126
  file_id = file['id']
127
  download_link = f"https://drive.google.com/uc?export=download&id={file_id}"
128
  return download_link
@@ -131,37 +181,25 @@ def upload_to_google_drive(file_path, folder_id):
131
  return None
132
 
133
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
134
- """Procesa la entrada del usuario y genera el video final."""
135
  try:
136
- # Determinamos el texto a usar
137
  if text.strip():
138
  final_text = text
139
  elif txt_file is not None:
140
  final_text = txt_file.decode("utf-8")
141
  else:
142
  raise ValueError("No text input provided")
143
-
144
- # Generamos el audio
145
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
146
  if not audio_file:
147
  raise ValueError("Failed to generate audio")
148
-
149
- # Generamos el video
150
  video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
151
  if not video_clip:
152
  raise ValueError("Failed to generate video")
153
-
154
- # Procesamos la m煤sica de fondo si existe
155
  music_clip = None
156
  if mp3_file is not None:
157
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
158
-
159
- # Combinamos todo
160
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
161
  if not final_video_path:
162
  raise ValueError("Failed to combine audio and video")
163
-
164
- # Subimos a Google Drive y obtenemos el enlace
165
  download_link = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
166
  if download_link:
167
  print(f"Video subido a Google Drive. Enlace de descarga: {download_link}")
@@ -172,9 +210,8 @@ def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keyword
172
  print(f"Error durante el procesamiento: {e}")
173
  return None
174
  finally:
175
- cleanup_temp_files() # Limpiar archivos temporales al finalizar
176
 
177
- # Interfaz Gradio
178
  with gr.Blocks() as demo:
179
  gr.Markdown("# Text-to-Video Generator")
180
  with gr.Row():
@@ -191,7 +228,7 @@ with gr.Blocks() as demo:
191
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
192
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
193
  with gr.Column():
194
- output_link = gr.Markdown("") # Mostrar el enlace de descarga
195
 
196
  btn = gr.Button("Generate Video")
197
  btn.click(
@@ -200,8 +237,6 @@ with gr.Blocks() as demo:
200
  outputs=output_link
201
  )
202
 
203
- # Leer el puerto asignado por Hugging Face
204
  port = int(os.getenv("PORT", 7860))
205
 
206
- # Lanzar la aplicaci贸n
207
  demo.launch(server_name="0.0.0.0", server_port=port, share=True, show_error=True)
 
17
  from googleapiclient.http import MediaFileUpload
18
  from io import BytesIO
19
 
 
20
  service_account_info = json.loads(os.getenv('GOOGLE_SERVICE_ACCOUNT', '{}'))
21
  if service_account_info:
22
  with open('service-account.json', 'w') as f:
23
  json.dump(service_account_info, f)
24
 
 
25
  output_folder = "outputs"
26
  temp_dir = "temp_files"
27
  os.makedirs(output_folder, exist_ok=True)
28
  os.makedirs(temp_dir, exist_ok=True)
29
 
30
+ FOLDER_ID = "12S6adpanAXjf71pKKGRRPqpzbJa5XEh3"
 
31
 
32
  def cleanup_temp_files():
 
33
  for filename in os.listdir(temp_dir):
34
  file_path = os.path.join(temp_dir, filename)
35
  try:
 
39
  print(f"Error deleting {file_path}: {e}")
40
 
41
  def resize_and_blur_video(clip, target_width=1920, target_height=1080):
42
+ try:
43
+ w, h = clip.size
44
+ current_aspect_ratio = w / h
45
+ target_aspect_ratio = target_width / target_height
46
+
47
+ if abs(current_aspect_ratio - target_aspect_ratio) < 0.1:
48
+ return clip.resize((target_width, target_height))
49
+
50
+ background = ColorClip(size=(target_width, target_height), color=[0, 0, 0]).set_duration(clip.duration)
51
+ try:
52
+ background = background.fx(vfx.blur, sigma=50)
53
+ except Exception as e:
54
+ print(f"Error al aplicar blur: {e}")
55
+
56
+ if current_aspect_ratio < target_aspect_ratio:
57
+ new_height = target_height
58
+ new_width = int(new_height * current_aspect_ratio)
59
+ x_center = (target_width - new_width) / 2
60
+ resized_clip = clip.resize(width=new_width).set_position((x_center, 0))
61
+ else:
62
+ new_width = target_width
63
+ new_height = int(new_width / current_aspect_ratio)
64
+ y_center = (target_height - new_height) / 2
65
+ resized_clip = clip.resize(height=new_height).set_position((0, y_center))
66
+
67
+ return CompositeVideoClip([background, resized_clip], size=(target_width, target_height))
68
+ except Exception as e:
69
+ print(f"Error en resize_and_blur_video: {e}")
70
+ return clip
71
 
72
  def download_video(link):
73
+ try:
74
+ video_response = requests.get(link)
75
+ if video_response.status_code != 200:
76
+ return None
77
+ temp_video_path = os.path.join(temp_dir, f"temp_video_{int(time.time())}.mp4")
78
+ with open(temp_video_path, "wb") as f:
79
+ f.write(video_response.content)
80
+ return temp_video_path
81
+ except Exception as e:
82
+ print(f"Error downloading video: {e}")
83
+ return None
84
 
85
  def concatenate_pixabay_videos(keywords, num_videos_per_keyword=1):
86
+ keyword_list = [keyword.strip() for keyword in keywords.split(",") if keyword.strip()]
87
+ if not keyword_list:
88
+ keyword_list = ["nature"]
89
+ video_clips = []
90
+ for keyword in keyword_list:
91
+ try:
92
+ print(f"Buscando videos para la palabra clave '{keyword}'...")
93
+ links = search_pixabay(keyword, num_results=num_videos_per_keyword)
94
+ if not links:
95
+ print(f"No se encontraron videos para '{keyword}', probando con 'nature'")
96
+ links = search_pixabay("nature", num_results=num_videos_per_keyword)
97
+ if not links:
98
+ continue
99
+ temp_video_path = download_video(links[0])
100
+ if temp_video_path:
101
+ clip = VideoFileClip(temp_video_path)
102
+ processed_clip = resize_and_blur_video(clip)
103
+ video_clips.append(processed_clip)
104
+ os.remove(temp_video_path)
105
+ except Exception as e:
106
+ print(f"Error procesando palabra clave '{keyword}': {e}")
107
+ continue
108
+ if not video_clips:
109
+ return ColorClip(size=(1920, 1080), color=[0, 0, 0], duration=5)
110
+ random.shuffle(video_clips)
111
+ return concatenate_videoclips(video_clips, method="compose")
112
 
113
  def adjust_background_music(video_duration, music_file):
114
+ try:
115
+ music = AudioFileClip(music_file)
116
+ if music.duration < video_duration:
117
+ repetitions = int(video_duration / music.duration) + 1
118
+ music_clips = [music] * repetitions
119
+ music = concatenate_audioclips(music_clips)
120
+ music = music.subclip(0, video_duration)
121
+ return music.volumex(0.2)
122
+ except Exception as e:
123
+ print(f"Error ajustando m煤sica: {e}")
124
+ return None
125
 
126
  def combine_audio_video(audio_file, video_clip, music_clip=None):
 
127
  try:
128
  audio_clip = AudioFileClip(audio_file)
129
+ total_duration = audio_clip.duration + 2
130
 
 
131
  video_clip = video_clip.loop(duration=total_duration)
132
  video_clip = video_clip.set_duration(total_duration).fadeout(2)
133
 
 
134
  final_clip = video_clip.set_audio(audio_clip)
 
 
135
  if music_clip:
136
  music_clip = music_clip.set_duration(total_duration).audio_fadeout(2)
137
  final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))
 
 
138
  output_filename = f"final_video_{int(time.time())}.mp4"
139
  output_path = os.path.join(output_folder, output_filename)
140
+
 
141
  final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
142
+
 
143
  final_clip.close()
144
  video_clip.close()
145
  audio_clip.close()
146
  if music_clip:
147
  music_clip.close()
148
+
149
  return output_path
 
150
  except Exception as e:
151
  print(f"Error combinando audio y video: {e}")
152
  if 'final_clip' in locals():
 
154
  return None
155
 
156
  def upload_to_google_drive(file_path, folder_id):
 
157
  try:
 
158
  creds = service_account.Credentials.from_service_account_file(
159
  'service-account.json', scopes=['https://www.googleapis.com/auth/drive']
160
  )
161
  service = build('drive', 'v3', credentials=creds)
162
 
 
163
  file_metadata = {
164
  'name': os.path.basename(file_path),
165
  'parents': [folder_id]
 
167
  media = MediaFileUpload(file_path, resumable=True)
168
  file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
169
 
 
170
  permission = {
171
  'type': 'anyone',
172
  'role': 'reader'
173
  }
174
  service.permissions().create(fileId=file['id'], body=permission).execute()
175
 
 
176
  file_id = file['id']
177
  download_link = f"https://drive.google.com/uc?export=download&id={file_id}"
178
  return download_link
 
181
  return None
182
 
183
  def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch, keywords):
 
184
  try:
 
185
  if text.strip():
186
  final_text = text
187
  elif txt_file is not None:
188
  final_text = txt_file.decode("utf-8")
189
  else:
190
  raise ValueError("No text input provided")
 
 
191
  audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
192
  if not audio_file:
193
  raise ValueError("Failed to generate audio")
 
 
194
  video_clip = concatenate_pixabay_videos(keywords, num_videos_per_keyword=1)
195
  if not video_clip:
196
  raise ValueError("Failed to generate video")
 
 
197
  music_clip = None
198
  if mp3_file is not None:
199
  music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
 
 
200
  final_video_path = combine_audio_video(audio_file, video_clip, music_clip)
201
  if not final_video_path:
202
  raise ValueError("Failed to combine audio and video")
 
 
203
  download_link = upload_to_google_drive(final_video_path, folder_id=FOLDER_ID)
204
  if download_link:
205
  print(f"Video subido a Google Drive. Enlace de descarga: {download_link}")
 
210
  print(f"Error durante el procesamiento: {e}")
211
  return None
212
  finally:
213
+ cleanup_temp_files()
214
 
 
215
  with gr.Blocks() as demo:
216
  gr.Markdown("# Text-to-Video Generator")
217
  with gr.Row():
 
228
  rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
229
  pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)
230
  with gr.Column():
231
+ output_link = gr.Markdown("")
232
 
233
  btn = gr.Button("Generate Video")
234
  btn.click(
 
237
  outputs=output_link
238
  )
239
 
 
240
  port = int(os.getenv("PORT", 7860))
241
 
 
242
  demo.launch(server_name="0.0.0.0", server_port=port, share=True, show_error=True)