Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -94,17 +94,22 @@ def create_video_from_images_ffmpeg_sequence(processed_image_folder, num_images,
|
|
| 94 |
video_filename_temp
|
| 95 |
]
|
| 96 |
|
|
|
|
| 97 |
try:
|
| 98 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
| 99 |
-
print("FFmpeg Image Sequence stdout:", result.stdout)
|
| 100 |
-
print("FFmpeg Image Sequence stderr:", result.stderr)
|
| 101 |
except subprocess.CalledProcessError as e:
|
|
|
|
| 102 |
raise Exception(f"Error al crear video desde imágenes con FFmpeg. Salida de error: {e.stderr}")
|
| 103 |
except FileNotFoundError:
|
|
|
|
| 104 |
raise Exception("Error: FFmpeg no encontrado. Asegúrate de que esté instalado en el entorno.")
|
| 105 |
|
| 106 |
if not os.path.exists(video_filename_temp):
|
|
|
|
| 107 |
raise IOError(f"Error: FFmpeg no creó el archivo de video {video_filename_temp} desde la secuencia de imágenes.")
|
|
|
|
| 108 |
return video_filename_temp
|
| 109 |
|
| 110 |
|
|
@@ -122,29 +127,22 @@ def combine_video_and_audio_ffmpeg(video_path, audio_path, output_path):
|
|
| 122 |
output_path
|
| 123 |
]
|
| 124 |
|
|
|
|
| 125 |
try:
|
| 126 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
| 127 |
-
print("FFmpeg combine stdout:", result.stdout)
|
| 128 |
-
print("FFmpeg combine stderr:", result.stderr)
|
| 129 |
except subprocess.CalledProcessError as e:
|
|
|
|
| 130 |
raise Exception(f"Error al combinar video y audio con FFmpeg. Salida de error: {e.stderr}")
|
| 131 |
except FileNotFoundError:
|
|
|
|
| 132 |
raise Exception("Error: FFmpeg no encontrado. Asegúrate de que esté instalado en el entorno.")
|
| 133 |
|
| 134 |
-
def
|
| 135 |
news_content = ""
|
| 136 |
-
|
| 137 |
-
error_message = ""
|
| 138 |
-
|
| 139 |
-
temp_audio_file = "audio_temp.mp3"
|
| 140 |
-
temp_video_no_audio = "video_no_audio_temp.mp4"
|
| 141 |
-
processed_image_folder = "temp_processed_images_for_video"
|
| 142 |
-
final_output_video_path = "output_news_video_final.mp4"
|
| 143 |
|
| 144 |
-
if os.path.exists(processed_image_folder):
|
| 145 |
-
shutil.rmtree(processed_image_folder)
|
| 146 |
-
os.makedirs(processed_image_folder, exist_ok=True)
|
| 147 |
-
|
| 148 |
if news_text_input:
|
| 149 |
news_content = news_text_input
|
| 150 |
elif gemini_prompt:
|
|
@@ -155,10 +153,44 @@ def create_news_video_app(news_text_input, gemini_prompt, image_files, video_rat
|
|
| 155 |
return "Por favor, escribe una noticia o proporciona un prompt para Gemini.", None
|
| 156 |
|
| 157 |
if not news_content:
|
| 158 |
-
return "No se pudo obtener el contenido de la noticia.
|
| 159 |
|
| 160 |
try:
|
| 161 |
text_to_speech(news_content, output_filename=temp_audio_file)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
audio_duration = get_audio_duration(temp_audio_file)
|
| 163 |
|
| 164 |
if not image_files:
|
|
@@ -189,10 +221,14 @@ def create_news_video_app(news_text_input, gemini_prompt, image_files, video_rat
|
|
| 189 |
|
| 190 |
except Exception as e:
|
| 191 |
error_message = f"Ocurrió un error: {e}"
|
|
|
|
| 192 |
return error_message, None
|
| 193 |
finally:
|
| 194 |
-
|
|
|
|
| 195 |
os.remove(temp_audio_file)
|
|
|
|
|
|
|
| 196 |
if os.path.exists(temp_video_no_audio):
|
| 197 |
os.remove(temp_video_no_audio)
|
| 198 |
if os.path.exists(processed_image_folder):
|
|
@@ -222,27 +258,39 @@ with gr.Blocks() as demo:
|
|
| 222 |
placeholder="Ej: Escribe una noticia sobre un nuevo récord mundial de ajedrez.",
|
| 223 |
value=""
|
| 224 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
image_upload = gr.File(
|
| 226 |
-
label="Sube de 1 a 60 imágenes (JPG, PNG)",
|
| 227 |
file_count="multiple",
|
| 228 |
type="filepath",
|
| 229 |
file_types=[".jpg", ".jpeg", ".png"]
|
| 230 |
)
|
| 231 |
video_ratio_dropdown = gr.Dropdown(
|
| 232 |
-
label="Relación de Aspecto del Video",
|
| 233 |
choices=["16:9", "9:16"],
|
| 234 |
value="16:9",
|
| 235 |
interactive=True
|
| 236 |
)
|
| 237 |
-
|
| 238 |
|
| 239 |
with gr.Column():
|
| 240 |
-
output_message = gr.Textbox(label="Estado", interactive=False)
|
| 241 |
video_output = gr.Video(label="Video de la Noticia")
|
| 242 |
|
| 243 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
fn=create_news_video_app,
|
| 245 |
-
inputs=[news_input, gemini_prompt_input, image_upload, video_ratio_dropdown],
|
| 246 |
outputs=[output_message, video_output]
|
| 247 |
)
|
| 248 |
|
|
|
|
| 94 |
video_filename_temp
|
| 95 |
]
|
| 96 |
|
| 97 |
+
print(f"DEBUG: FFmpeg image sequence command: {' '.join(command)}")
|
| 98 |
try:
|
| 99 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
| 100 |
+
print("DEBUG: FFmpeg Image Sequence stdout:", result.stdout)
|
| 101 |
+
print("DEBUG: FFmpeg Image Sequence stderr:", result.stderr)
|
| 102 |
except subprocess.CalledProcessError as e:
|
| 103 |
+
print(f"DEBUG: FFmpeg Image Sequence CalledProcessError: {e.stderr}")
|
| 104 |
raise Exception(f"Error al crear video desde imágenes con FFmpeg. Salida de error: {e.stderr}")
|
| 105 |
except FileNotFoundError:
|
| 106 |
+
print("DEBUG: FFmpeg not found during image sequence creation.")
|
| 107 |
raise Exception("Error: FFmpeg no encontrado. Asegúrate de que esté instalado en el entorno.")
|
| 108 |
|
| 109 |
if not os.path.exists(video_filename_temp):
|
| 110 |
+
print(f"DEBUG: {video_filename_temp} does not exist after FFmpeg run.")
|
| 111 |
raise IOError(f"Error: FFmpeg no creó el archivo de video {video_filename_temp} desde la secuencia de imágenes.")
|
| 112 |
+
print(f"DEBUG: {video_filename_temp} successfully created by FFmpeg.")
|
| 113 |
return video_filename_temp
|
| 114 |
|
| 115 |
|
|
|
|
| 127 |
output_path
|
| 128 |
]
|
| 129 |
|
| 130 |
+
print(f"DEBUG: FFmpeg combine command: {' '.join(command)}")
|
| 131 |
try:
|
| 132 |
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
| 133 |
+
print("DEBUG: FFmpeg combine stdout:", result.stdout)
|
| 134 |
+
print("DEBUG: FFmpeg combine stderr:", result.stderr)
|
| 135 |
except subprocess.CalledProcessError as e:
|
| 136 |
+
print(f"DEBUG: FFmpeg combine CalledProcessError: {e.stderr}")
|
| 137 |
raise Exception(f"Error al combinar video y audio con FFmpeg. Salida de error: {e.stderr}")
|
| 138 |
except FileNotFoundError:
|
| 139 |
+
print("DEBUG: FFmpeg not found during combine.")
|
| 140 |
raise Exception("Error: FFmpeg no encontrado. Asegúrate de que esté instalado en el entorno.")
|
| 141 |
|
| 142 |
+
def generate_tts_only(news_text_input, gemini_prompt):
|
| 143 |
news_content = ""
|
| 144 |
+
temp_audio_file = "audio_temp_preview.mp3"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
if news_text_input:
|
| 147 |
news_content = news_text_input
|
| 148 |
elif gemini_prompt:
|
|
|
|
| 153 |
return "Por favor, escribe una noticia o proporciona un prompt para Gemini.", None
|
| 154 |
|
| 155 |
if not news_content:
|
| 156 |
+
return "No se pudo obtener el contenido de la noticia.", None
|
| 157 |
|
| 158 |
try:
|
| 159 |
text_to_speech(news_content, output_filename=temp_audio_file)
|
| 160 |
+
return "Audio generado con éxito.", temp_audio_file
|
| 161 |
+
except Exception as e:
|
| 162 |
+
return f"Ocurrió un error al generar solo el audio: {e}", None
|
| 163 |
+
|
| 164 |
+
def create_news_video_app(news_text_input, gemini_prompt, image_files, video_ratio, input_audio_file=None):
|
| 165 |
+
news_content = ""
|
| 166 |
+
output_video_path = None
|
| 167 |
+
error_message = ""
|
| 168 |
+
|
| 169 |
+
temp_audio_file = input_audio_file if input_audio_file and os.path.exists(input_audio_file) else "audio_temp_for_video.mp3"
|
| 170 |
+
temp_video_no_audio = "video_no_audio_temp.mp4"
|
| 171 |
+
processed_image_folder = "temp_processed_images_for_video"
|
| 172 |
+
final_output_video_path = "output_news_video_final.mp4"
|
| 173 |
+
|
| 174 |
+
if os.path.exists(processed_image_folder):
|
| 175 |
+
shutil.rmtree(processed_image_folder)
|
| 176 |
+
os.makedirs(processed_image_folder, exist_ok=True)
|
| 177 |
+
|
| 178 |
+
try:
|
| 179 |
+
if not input_audio_file or not os.path.exists(input_audio_file):
|
| 180 |
+
if news_text_input:
|
| 181 |
+
news_content = news_text_input
|
| 182 |
+
elif gemini_prompt:
|
| 183 |
+
news_content = generate_news_with_gemini(gemini_prompt)
|
| 184 |
+
if "Error" in news_content:
|
| 185 |
+
return news_content, None
|
| 186 |
+
else:
|
| 187 |
+
return "Por favor, escribe una noticia, proporciona un prompt para Gemini, o genera el audio primero.", None
|
| 188 |
+
|
| 189 |
+
if not news_content:
|
| 190 |
+
return "No se pudo obtener el contenido de la noticia. Intenta con un prompt diferente o escribe directamente.", None
|
| 191 |
+
|
| 192 |
+
text_to_speech(news_content, output_filename=temp_audio_file)
|
| 193 |
+
|
| 194 |
audio_duration = get_audio_duration(temp_audio_file)
|
| 195 |
|
| 196 |
if not image_files:
|
|
|
|
| 221 |
|
| 222 |
except Exception as e:
|
| 223 |
error_message = f"Ocurrió un error: {e}"
|
| 224 |
+
print(f"DEBUG: Error caught in main app function: {e}")
|
| 225 |
return error_message, None
|
| 226 |
finally:
|
| 227 |
+
# Clean up all temporary files
|
| 228 |
+
if os.path.exists(temp_audio_file) and temp_audio_file != input_audio_file:
|
| 229 |
os.remove(temp_audio_file)
|
| 230 |
+
if os.path.exists("audio_temp_preview.mp3"):
|
| 231 |
+
os.remove("audio_temp_preview.mp3") # Clean up preview audio if it exists
|
| 232 |
if os.path.exists(temp_video_no_audio):
|
| 233 |
os.remove(temp_video_no_audio)
|
| 234 |
if os.path.exists(processed_image_folder):
|
|
|
|
| 258 |
placeholder="Ej: Escribe una noticia sobre un nuevo récord mundial de ajedrez.",
|
| 259 |
value=""
|
| 260 |
)
|
| 261 |
+
|
| 262 |
+
# Botón intermedio para generar solo audio
|
| 263 |
+
generate_audio_button = gr.Button("1. Generar Solo Audio")
|
| 264 |
+
audio_output_preview = gr.Audio(label="Audio de Noticia (Vista Previa)", interactive=False)
|
| 265 |
+
audio_status_message = gr.Textbox(label="Estado del Audio", interactive=False)
|
| 266 |
+
|
| 267 |
image_upload = gr.File(
|
| 268 |
+
label="2. Sube de 1 a 60 imágenes (JPG, PNG)",
|
| 269 |
file_count="multiple",
|
| 270 |
type="filepath",
|
| 271 |
file_types=[".jpg", ".jpeg", ".png"]
|
| 272 |
)
|
| 273 |
video_ratio_dropdown = gr.Dropdown(
|
| 274 |
+
label="3. Relación de Aspecto del Video",
|
| 275 |
choices=["16:9", "9:16"],
|
| 276 |
value="16:9",
|
| 277 |
interactive=True
|
| 278 |
)
|
| 279 |
+
generate_video_button = gr.Button("4. Generar Video de Noticia")
|
| 280 |
|
| 281 |
with gr.Column():
|
| 282 |
+
output_message = gr.Textbox(label="Estado del Video", interactive=False)
|
| 283 |
video_output = gr.Video(label="Video de la Noticia")
|
| 284 |
|
| 285 |
+
generate_audio_button.click(
|
| 286 |
+
fn=generate_tts_only,
|
| 287 |
+
inputs=[news_input, gemini_prompt_input],
|
| 288 |
+
outputs=[audio_status_message, audio_output_preview]
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
generate_video_button.click(
|
| 292 |
fn=create_news_video_app,
|
| 293 |
+
inputs=[news_input, gemini_prompt_input, image_upload, video_ratio_dropdown, audio_output_preview],
|
| 294 |
outputs=[output_message, video_output]
|
| 295 |
)
|
| 296 |
|