gnosticdev commited on
Commit
15e8c2d
·
verified ·
1 Parent(s): 8b274aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -71
app.py CHANGED
@@ -1,87 +1,134 @@
1
- import gradio as gr
2
- import edge_tts
3
- import asyncio
4
  import os
 
5
  import logging
6
- import torch
7
- from transformers import pipeline, set_seed
8
- from moviepy.editor import *
9
- from dotenv import load_dotenv
10
-
11
- # Configurar logs visibles en Hugging Face
12
- logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
13
 
14
- # Cargar variables de entorno si hay .env
15
- load_dotenv()
16
 
17
- # Verificar si CUDA está disponible
18
- device = 0 if torch.cuda.is_available() else -1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- # Inicializar generador de texto
21
- generator = pipeline("text-generation", model="gpt2", device=device)
22
- set_seed(42)
23
 
24
- # Asíncrono: convertir texto a voz con edge-tts
25
- async def text_to_speech(text, output_path, voice="es-MX-DaliaNeural"):
26
- tts = edge_tts.Communicate(text=text, voice=voice)
27
- await tts.save(output_path)
28
 
29
- def generate_video(prompt, background_music_path="musica.mp3"):
30
- logging.info("🚀 Generando guion con IA...")
31
- result = generator(prompt, max_length=500, do_sample=True, truncation=True)
32
- script = result[0]['generated_text']
33
- logging.info("🗣 Guion generado.")
34
 
35
- # Guardar guion a texto plano
36
- with open("guion.txt", "w") as f:
37
- f.write(script)
38
 
39
- # Convertir texto a voz (bloqueo controlado)
40
- output_audio = "voz.mp3"
41
  try:
42
- asyncio.run(text_to_speech(script, output_audio))
43
- logging.info("🎤 Voz generada.")
 
44
  except Exception as e:
45
- logging.error(f"Error generando voz: {e}")
46
- return None, script
47
-
48
- # Cargar clip de voz
49
- voice_clip = AudioFileClip(output_audio)
50
- duration = voice_clip.duration
51
-
52
- # Video negro (fondo) + voz
53
- video = ColorClip(size=(1280, 720), color=(0, 0, 0), duration=duration)
54
-
55
- # Música en loop si es más corta que la voz
56
- if os.path.exists(background_music_path):
57
- music = AudioFileClip(background_music_path)
58
- if music.duration < duration:
59
- loops = int(duration // music.duration) + 1
60
- music = concatenate_audioclips([music] * loops)
61
- music = music.subclip(0, duration)
62
- final_audio = CompositeAudioClip([music.volumex(0.2), voice_clip])
63
- else:
64
- final_audio = voice_clip
65
 
66
- video = video.set_audio(final_audio)
67
- output_path = "video_generado.mp4"
68
- video.write_videofile(output_path, fps=24, codec="libx264", audio_codec="aac")
69
-
70
- return output_path, script
71
-
72
- # Interfaz de Gradio
73
  with gr.Blocks() as app:
74
- gr.Markdown("# 🎬 Generador de video IA + Voz + Música")
75
- prompt = gr.Textbox(label="Prompt del guion")
 
 
76
  boton = gr.Button("Generar video")
77
- salida_video = gr.Video()
78
- salida_texto = gr.Textbox(label="Guion generado")
79
-
80
- def ejecutar(prompt):
81
- video, script = generate_video(prompt)
82
- return video, script
83
 
84
- boton.click(ejecutar, inputs=prompt, outputs=[salida_video, salida_texto])
85
 
86
- # Lanzar app
87
- app.launch(debug=True)
 
 
 
 
1
  import os
2
+ import asyncio
3
  import logging
4
+ import tempfile
5
+ import requests
6
+ from datetime import datetime
7
+ from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, afx
8
+ import edge_tts
9
+ import gradio as gr
 
10
 
11
+ from transformers import GPT2Tokenizer, GPT2LMHeadModel
12
+ import torch
13
 
14
+ logging.basicConfig(level=logging.INFO)
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Inicializa tokenizer y modelo (puedes cambiar modelo si quieres)
18
+ tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
19
+ model = GPT2LMHeadModel.from_pretrained("gpt2").eval()
20
+
21
+ def generate_script(prompt, max_length=300):
22
+ logger.info("Generando guion...")
23
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=False)
24
+ with torch.no_grad():
25
+ outputs = model.generate(
26
+ **inputs,
27
+ max_length=max_length,
28
+ do_sample=True,
29
+ top_p=0.95,
30
+ top_k=60,
31
+ temperature=0.9,
32
+ pad_token_id=tokenizer.eos_token_id
33
+ )
34
+ text = tokenizer.decode(outputs[0], skip_special_tokens=True)
35
+ logger.info(f"Guion generado, longitud: {len(text)} caracteres")
36
+ return text
37
+
38
+ async def text_to_speech(text, voice="es-ES-ElviraNeural", output_path="voz.mp3"):
39
+ logger.info("Generando audio TTS...")
40
+ communicate = edge_tts.Communicate(text, voice)
41
+ await communicate.save(output_path)
42
+ logger.info(f"Audio guardado en {output_path}")
43
+
44
+ def download_video_sample(url):
45
+ logger.info(f"Descargando video de ejemplo: {url}")
46
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
47
+ response = requests.get(url, stream=True)
48
+ for chunk in response.iter_content(chunk_size=1024*1024):
49
+ tmp.write(chunk)
50
+ tmp.close()
51
+ return tmp.name
52
+
53
+ def loop_audio_to_length(audio_clip, target_duration):
54
+ if audio_clip.duration >= target_duration:
55
+ return audio_clip.subclip(0, target_duration)
56
+ loops = int(target_duration // audio_clip.duration) + 1
57
+ audios = [audio_clip] * loops
58
+ concatenated = concatenate_videoclips(audios, method="compose")
59
+ return concatenated.subclip(0, target_duration)
60
+
61
+ def crear_video(prompt, musica_url=None):
62
+ # 1. Generar guion
63
+ guion = generate_script(prompt, max_length=300)
64
+
65
+ # 2. TTS
66
+ voz_archivo = "voz.mp3"
67
+ asyncio.run(text_to_speech(guion, output_path=voz_archivo))
68
+
69
+ # 3. Descargar videos de ejemplo (puedes reemplazar por tu búsqueda real)
70
+ # Aquí pongo 3 clips de ejemplo (deberías poner tus URLs)
71
+ video_urls = [
72
+ "https://sample-videos.com/video123/mp4/240/big_buck_bunny_240p_1mb.mp4",
73
+ "https://sample-videos.com/video123/mp4/240/big_buck_bunny_240p_1mb.mp4",
74
+ "https://sample-videos.com/video123/mp4/240/big_buck_bunny_240p_1mb.mp4"
75
+ ]
76
+ clips = []
77
+ for url in video_urls[:3]:
78
+ video_path = download_video_sample(url)
79
+ clip = VideoFileClip(video_path).subclip(0, 10) # máximo 10 segundos
80
+ clips.append(clip)
81
+
82
+ # 4. Concatenar videos
83
+ video_final = concatenate_videoclips(clips, method="compose")
84
+
85
+ # 5. Cargar audio TTS
86
+ audio_tts = AudioFileClip(voz_archivo)
87
+
88
+ # 6. Música de fondo en loop si está definida
89
+ if musica_url:
90
+ musica_path = download_video_sample(musica_url)
91
+ musica_audio = AudioFileClip(musica_path)
92
+ # Loop música a duración voz
93
+ musica_loop = loop_audio_to_length(musica_audio, audio_tts.duration)
94
+ # Mezclar audio TTS y música
95
+ mezcla = CompositeAudioClip([musica_loop.volumex(0.3), audio_tts.volumex(1.0)])
96
+ else:
97
+ mezcla = audio_tts
98
 
99
+ # 7. Asignar audio al video
100
+ video_final = video_final.set_audio(mezcla).subclip(0, audio_tts.duration)
 
101
 
102
+ # 8. Guardar video final
103
+ output_path = f"video_output_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
104
+ video_final.write_videofile(output_path, fps=24, threads=2, logger=None)
 
105
 
106
+ # 9. Limpiar archivos temporales
107
+ os.remove(voz_archivo)
108
+ for clip in clips:
109
+ clip.close()
 
110
 
111
+ return output_path
 
 
112
 
113
+ def run_app(prompt, musica_url):
114
+ logger.info(f"Entrada recibida: {prompt}")
115
  try:
116
+ video_path = crear_video(prompt, musica_url if musica_url.strip() else None)
117
+ logger.info(f"Video generado en: {video_path}")
118
+ return video_path
119
  except Exception as e:
120
+ logger.error(f"Error durante la generación: {e}")
121
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
 
 
 
 
 
 
 
123
  with gr.Blocks() as app:
124
+ gr.Markdown("### Generador simple de video con texto, voz y música en loop")
125
+ with gr.Row():
126
+ prompt_input = gr.Textbox(label="Introduce el tema para generar el guion", lines=2)
127
+ musica_input = gr.Textbox(label="URL de música (opcional) para usar de fondo")
128
  boton = gr.Button("Generar video")
129
+ salida = gr.Video(label="Video generado")
 
 
 
 
 
130
 
131
+ boton.click(run_app, inputs=[prompt_input, musica_input], outputs=salida)
132
 
133
+ if __name__ == "__main__":
134
+ app.launch(server_name="0.0.0.0", server_port=7860)