import gradio as gr import asyncio import edge_tts import requests import tempfile import os from datetime import datetime from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip # Voz predeterminada (puedes cambiarla o cargar lista) VOCES = [{'ShortName': 'es-ES-ElviraNeural', 'Name': 'Elvira', 'Gender': 'Female'}] VOICE_NAMES = [f"{v['Name']} ({v['Gender']})" for v in VOCES] # Simula función para generar texto según prompt def generar_texto(prompt): # Aquí deberías integrar tu generador real, por ahora solo repetimos prompt return f"Este es un texto generado para el tema: {prompt}" # Simula función para buscar videos (debes conectar con Pexels u otra API) def buscar_videos(prompt): # Retorna lista simulada con links a videos (debes poner tu API real) return [ { "video_files": [{"link": "https://filesamples.com/samples/video/mp4/sample_640x360.mp4"}], "duration": 10 }, { "video_files": [{"link": "https://filesamples.com/samples/video/mp4/sample_640x360.mp4"}], "duration": 10 } ] async def crear_video(prompt, voz_index, musica_path=None): try: texto = generar_texto(prompt) voz_shortname = VOCES[voz_index]['ShortName'] # Generar audio TTS archivo_audio = "audio.mp3" await edge_tts.Communicate(texto, voz_shortname).save(archivo_audio) audio_clip = AudioFileClip(archivo_audio) duracion_audio = audio_clip.duration # Cargar música si se pasa if musica_path: musica_clip = AudioFileClip(musica_path).volumex(0.2) # Volumen bajo para música musica_clip = musica_clip.subclip(0, duracion_audio) audio_final = CompositeAudioClip([musica_clip, audio_clip]) else: audio_final = audio_clip # Descargar y preparar videos videos = buscar_videos(prompt) if not videos: return None clips = [] for v in videos[:3]: video_url = v['video_files'][0]['link'] response = requests.get(video_url, stream=True) temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") for chunk in response.iter_content(chunk_size=1024*1024): temp_file.write(chunk) temp_file.close() clip = VideoFileClip(temp_file.name).subclip(0, min(duracion_audio/len(videos), v['duration'])) clips.append(clip) video_final = concatenate_videoclips(clips) video_final = video_final.set_audio(audio_final) output_filename = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4" video_final.write_videofile(output_filename, codec="libx264", audio_codec="aac", fps=24) # Limpieza audio_clip.close() if musica_path: musica_clip.close() for c in clips: c.close() os.remove(c.filename) os.remove(archivo_audio) return output_filename except Exception as e: return f"Error: {e}" def run_crear_video(prompt, voz_nombre, musica_file): try: voz_index = VOICE_NAMES.index(voz_nombre) except ValueError: voz_index = 0 musica_path = musica_file.name if musica_file else None return asyncio.run(crear_video(prompt, voz_index, musica_path)) with gr.Blocks(title="Generador de Video con TTS y Música de Fondo") as demo: with gr.Row(): with gr.Column(): prompt = gr.Textbox(label="Tema del video", lines=2) voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0]) musica = gr.File(label="Sube música de fondo (opcional, mp3/wav)", file_types=[".mp3", ".wav"]) btn = gr.Button("Generar Video") with gr.Column(): salida = gr.Video(label="Video generado") btn.click(run_crear_video, inputs=[prompt, voz, musica], outputs=salida) if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)