File size: 7,128 Bytes
3386266
2740481
aa29714
d4c89ff
 
2740481
 
 
 
 
 
4c8a9c1
 
 
 
 
d476eea
dc833d2
d4c89ff
dc833d2
d476eea
4c8a9c1
dc833d2
 
d4c89ff
dc833d2
 
 
d476eea
0594fa6
724ed17
 
 
 
 
 
 
 
0594fa6
724ed17
 
dc1e7fd
 
 
 
 
 
 
 
d4c89ff
 
dc1e7fd
 
 
 
 
 
 
 
 
 
 
 
 
 
9abb848
dc1e7fd
af20d0a
dc1e7fd
a75af72
724ed17
 
af20d0a
9abb848
 
 
 
af20d0a
9abb848
af20d0a
a75af72
9abb848
af20d0a
 
724ed17
af20d0a
 
724ed17
a75af72
 
 
 
 
 
 
 
 
 
 
 
724ed17
af20d0a
 
724ed17
0594fa6
724ed17
 
d476eea
0594fa6
724ed17
aa29714
724ed17
aa29714
724ed17
 
 
 
2740481
661caf6
2740481
 
aa29714
2740481
aa29714
2740481
aa29714
 
724ed17
dc1e7fd
724ed17
af20d0a
724ed17
 
 
2740481
724ed17
 
 
 
 
a75af72
724ed17
 
 
 
 
3386266
d476eea
3386266
 
 
 
 
 
 
2740481
aa29714
2740481
 
724ed17
3386266
 
 
 
2740481
 
0594fa6
2740481
 
3386266
3c4ac90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import gradio as gr
from tts_module import get_voices, text_to_speech  # Usamos el tts_module.py actualizado
from pexels_api import search_pexels
from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips

import asyncio
import os
import requests
import tempfile

# Forzar instalación de moviepy si no está disponible
def install(package):
    import subprocess
    import sys
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

try:
    # Intentar importar moviepy.editor
    from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
    print("MoviePy.editor está instalado correctamente.")
except ImportError:
    print("Instalando MoviePy...")
    install("moviepy==1.0.3")  # Forzar instalación de la versión compatible
    try:
        from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip, concatenate_audioclips, concatenate_videoclips
        print("MoviePy.editor instalado con éxito después de la reinstalación.")
    except ImportError:
        raise ImportError("Error crítico: No se pudo instalar moviepy.editor. Verifica las dependencias.")

# Ajustar música de fondo (repetición automática)
def adjust_background_music(video_duration, music_file):
    music = AudioFileClip(music_file)
    if music.duration < video_duration:
        repetitions = int(video_duration / music.duration) + 1
        music_clips = [music] * repetitions
        music = concatenate_audioclips(music_clips)
    if music.duration > video_duration:
        music = music.subclip(0, video_duration)
    music = music.volumex(0.2)  # Reducir volumen al 20%
    return music

# Concatenar múltiples videos de Pexels
def concatenate_pexels_videos(text, num_videos=5):
    sentences = [sentence.strip() for sentence in text.split(".") if sentence.strip()]
    video_links = []

    for sentence in sentences:
        try:
            links = search_pexels(sentence, num_results=num_videos)
            if links:
                video_links.append(links[0])  # Usamos el primer video encontrado para cada frase
        except Exception as e:
            print(f"Error al buscar video para la frase '{sentence}': {e}")
            continue

    if not video_links:
        raise Exception("No se encontraron videos relevantes para el texto proporcionado.")

    video_clips = []
    for link in video_links:
        video_response = requests.get(link)
        with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_video:
            tmp_video.write(video_response.content)
            video_clips.append(VideoFileClip(tmp_video.name))

    # Concatenar videos
    final_clip = concatenate_videoclips(video_clips, method="compose")
    return final_clip

# Combinar audio, video y música con fade out solo en el video y la música
def combine_audio_video(audio_file, video_clip, music_clip=None):
    audio_clip = AudioFileClip(audio_file)

    # Duración total: speech + 5 segundos para fade out
    total_duration = audio_clip.duration + 5

    # Extender la duración del video si es más corto que el audio + fade out
    if video_clip.duration < total_duration:
        video_clip = video_clip.loop(duration=total_duration)  # Repetir el video si es necesario

    # Aplicar fade out solo al video
    video_clip = video_clip.set_duration(total_duration).fadeout(5)

    # Combinar audio y video
    final_clip = video_clip.set_audio(audio_clip)

    # Añadir música de fondo si aplica
    if music_clip:
        # Extender la música para que coincida con la duración total
        if music_clip.duration < total_duration:
            repetitions = int(total_duration / music_clip.duration) + 1
            music_clips = [music_clip] * repetitions
            music_clip = concatenate_audioclips(music_clips)
        if music_clip.duration > total_duration:
            music_clip = music_clip.subclip(0, total_duration)

        # Aplicar fade out a la música
        music_clip = music_clip.audio_fadeout(5)

        # Combinar audio principal, música y video
        final_clip = final_clip.set_audio(CompositeAudioClip([audio_clip, music_clip]))

    # Exportar el video final
    output_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
    final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
    return output_path

# Función principal
def process_input(text, txt_file, mp3_file, selected_voice, rate, pitch):
    try:
        if text.strip():
            final_text = text
        elif txt_file is not None:
            final_text = txt_file.decode("utf-8")
        else:
            return "No input provided", None

        # Obtener voces disponibles
        voices = asyncio.run(get_voices())
        if selected_voice not in voices:
            return f"La voz '{selected_voice}' no es válida. Por favor, seleccione una de las siguientes voces: {', '.join(voices.keys())}", None

        # Generar audio con edge_tts
        try:
            audio_file = asyncio.run(text_to_speech(final_text, selected_voice, rate, pitch))
        except Exception as e:
            return f"Error con la voz seleccionada: {e}", None

        # Concatenar múltiples videos de Pexels basados en el texto
        try:
            video_clip = concatenate_pexels_videos(final_text, num_videos=5)
        except Exception as e:
            return f"Error al buscar videos en Pexels: {e}", None

        # Ajustar música de fondo
        if mp3_file is not None:
            music_clip = adjust_background_music(video_clip.duration, mp3_file.name)
        else:
            music_clip = None

        # Combinar audio, video y música con fade out solo en el video y la música
        final_video = combine_audio_video(audio_file, video_clip, music_clip)
        return final_video

    except Exception as e:
        return f"Error durante el procesamiento: {e}", None

# Interfaz Gradio
with gr.Blocks() as demo:
    gr.Markdown("# Text-to-Video Generator")
    with gr.Row():
        with gr.Column():
            text_input = gr.Textbox(label="Write your text here", lines=5)
            txt_file_input = gr.File(label="Or upload a .txt file", file_types=[".txt"])
            mp3_file_input = gr.File(label="Upload background music (.mp3)", file_types=[".mp3"])
            voices = asyncio.run(get_voices())  # Obtener voces disponibles
            voice_dropdown = gr.Dropdown(choices=list(voices.keys()), label="Select Voice")
            rate_slider = gr.Slider(minimum=-50, maximum=50, value=0, label="Speech Rate Adjustment (%)", step=1)
            pitch_slider = gr.Slider(minimum=-20, maximum=20, value=0, label="Pitch Adjustment (Hz)", step=1)

        with gr.Column():
            output_video = gr.Video(label="Generated Video")

    btn = gr.Button("Generate Video")
    btn.click(
        process_input,
        inputs=[text_input, txt_file_input, mp3_file_input, voice_dropdown, rate_slider, pitch_slider],
        outputs=output_video
    )

demo.launch()